This is an automated email from the ASF dual-hosted git repository.

eallen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/master by this push:
     new 9a6eda8  DISPATCH-1474 Ensure all inter-router links are included in 
the console's traffic view
9a6eda8 is described below

commit 9a6eda8fd2103afc7af225f08b5d81643c56c63e
Author: Ernest Allen <eal...@redhat.com>
AuthorDate: Wed Dec 11 17:36:31 2019 -0500

    DISPATCH-1474 Ensure all inter-router links are included in the console's 
traffic view
---
 console/react/src/topology/traffic.js | 631 ++++++++++++++++++++--------------
 1 file changed, 379 insertions(+), 252 deletions(-)

diff --git a/console/react/src/topology/traffic.js 
b/console/react/src/topology/traffic.js
index 4b4caa8..14fc172 100644
--- a/console/react/src/topology/traffic.js
+++ b/console/react/src/topology/traffic.js
@@ -24,18 +24,16 @@ import { nextHop } from "./topoUtils.js";
 import { utils } from "../common/amqp/utilities.js";
 
 const transitionDuration = 1000;
-//const CHORDFILTERKEY = "chordFilter";
 
 export class Traffic {
   // eslint-disable-line no-unused-vars
-  constructor($scope, QDRService, converter, radius, topology, types) {
+  constructor($scope, QDRService, converter, radius, topology, types, 
addressesChanged) {
     this.QDRService = QDRService;
+    this.addressesChanged = addressesChanged;
     this.types = [];
     this.viss = [];
     this.topology = topology; // contains the list of router nodes
     this.$scope = $scope;
-    this.addresses = $scope.state.legendOptions.traffic.addresses;
-    this.addressColors = $scope.state.legendOptions.traffic.addressColors;
     // internal variables
     this.interval = null; // setInterval handle
     types.forEach(
@@ -43,7 +41,7 @@ export class Traffic {
         this.addAnimationType(t, converter, radius);
       }.bind(this)
     );
-    // called by angular when mouse enters one of the address legends
+    // called when mouse enters one of the address legends
     this.$scope.enterLegend = address => {
       // fade all flows that aren't for this address
       this.fadeOtherAddresses(address);
@@ -72,6 +70,7 @@ export class Traffic {
   // start updating the traffic data
   start() {
     this.stop();
+    this.setup();
     this.doUpdate();
     this.interval = setInterval(this.doUpdate.bind(this), transitionDuration);
   }
@@ -99,10 +98,44 @@ export class Traffic {
     }
     this.start();
   }
+  // set the data needed for each animation
+  setup() {
+    this.viss.forEach(v => v.setup());
+  }
   // called periodically to refresh the traffic flow
   doUpdate() {
+    if (!this.interval) return;
     this.viss.forEach(v => v.doUpdate());
   }
+
+  setTopology(topology) {
+    this.topology = topology;
+  }
+
+  getAddressColors(service, converter) {
+    return Dots.getAddressColors(service, converter);
+  }
+
+  updateAddressColors(address, checked) {
+    if (addressColors[address]) {
+      addressColors[address].checked = checked;
+    }
+    this.updateDots();
+  }
+
+  updateDots() {
+    const dots = this.viss.find(v => v.type === "dots");
+    if (dots) {
+      const excludedAddresses = Object.keys(addressColors).filter(
+        address => !addressColors[address].checked
+      );
+      dots.updateAddresses(excludedAddresses);
+    }
+  }
+
+  addressColors() {
+    return addressColors;
+  }
 }
 
 /* Base class for congestion and dots visualizations */
@@ -129,6 +162,7 @@ class TrafficAnimation {
   }
 }
 
+const STEPS = 6;
 /* Color the links between router to show how heavily used the links are. */
 class Congestion extends TrafficAnimation {
   constructor(traffic) {
@@ -136,6 +170,18 @@ class Congestion extends TrafficAnimation {
     this.type = "congestion";
     this.stopped = false;
   }
+
+  setup() {
+    this.traffic.QDRService.management.topology.addUpdateEntities([
+      {
+        entity: "router.link"
+      },
+      {
+        entity: "connection"
+      }
+    ]);
+  }
+
   findResult(node, entity, attribute, value) {
     let attrIndex = node[entity].attributeNames.indexOf(attribute);
     if (attrIndex >= 0) {
@@ -147,105 +193,106 @@ class Congestion extends TrafficAnimation {
     }
     return null;
   }
+
   doUpdate() {
     this.stopped = false;
     let self = this;
-    this.traffic.QDRService.management.topology.ensureAllEntities(
-      [
-        {
-          entity: "router.link",
-          force: true
-        },
-        {
-          entity: "connection"
-        }
-      ],
-      function() {
-        // animation was stopped between the ensureAllEntities request and the 
response
-        if (self.stopped) return;
-        let links = {};
-        let nodeInfo = self.traffic.QDRService.management.topology.nodeInfo();
-        const nodes = self.traffic.topology.nodes.nodes;
-        const srv = self.traffic.QDRService;
-        // accumulate all the inter-router links in an object
-        // keyed by the svgs path id
-        for (let nodeId in nodeInfo) {
-          let node = nodeInfo[nodeId];
-          let nodeLinks = node["router.link"];
-          if (!nodeLinks) continue;
-          for (let n = 0; n < nodeLinks.results.length; n++) {
-            let link = srv.utilities.flatten(
-              nodeLinks.attributeNames,
-              nodeLinks.results[n]
-            );
-            if (link.linkType !== "router-control") {
-              let f = self.nodeIndexFor(nodes, 
srv.utilities.nameFromId(nodeId));
-              let connection = self.findResult(
-                node,
-                "connection",
-                "identity",
-                link.connectionId
+    // animation was stopped between the ensureAllEntities request and the 
response
+    if (self.stopped) return;
+    let links = {};
+    let nodeInfo = self.traffic.QDRService.management.topology.nodeInfo();
+    const nodes = self.traffic.topology.nodes.nodes;
+    const srv = self.traffic.QDRService;
+    // accumulate all the inter-router links in an object
+    // keyed by the svgs path id
+    for (let nodeId in nodeInfo) {
+      let node = nodeInfo[nodeId];
+      let nodeLinks = node["router.link"];
+      if (!nodeLinks) continue;
+      for (let n = 0; n < nodeLinks.results.length; n++) {
+        let link = srv.utilities.flatten(nodeLinks.attributeNames, 
nodeLinks.results[n]);
+        if (link.linkType !== "router-control") {
+          let f = self.nodeIndexFor(nodes, srv.utilities.nameFromId(nodeId));
+          let connection = self.findResult(
+            node,
+            "connection",
+            "identity",
+            link.connectionId
+          );
+          if (connection) {
+            let t = self.nodeIndexFor(nodes, connection.container);
+            let little = Math.min(f, t);
+            let big = Math.max(f, t);
+            if (little >= 0) {
+              let key = ["#hitpath", nodes[little].uid(srv), 
nodes[big].uid(srv)].join(
+                "-"
               );
-              if (connection) {
-                let t = self.nodeIndexFor(nodes, connection.container);
-                let little = Math.min(f, t);
-                let big = Math.max(f, t);
-                if (little >= 0) {
-                  let key = ["#path", nodes[little].uid(srv), 
nodes[big].uid(srv)].join(
-                    "-"
-                  );
-                  if (!links[key]) links[key] = [];
-                  links[key].push(link);
-                }
-              }
+              if (!links[key]) links[key] = [];
+              links[key].push(link);
             }
           }
         }
-        // accumulate the colors/directions to be used
-        for (let key in links) {
-          let congestion = self.congestion(links[key]);
-          let pathId = key.replace(/\./g, "\\.").replace(/ /g, "\\ ");
-          let path = d3.select(pathId);
-          if (path && !path.empty()) {
-            path
-              .transition()
-              .duration(1000)
-              .style("stroke", congestion)
-              .each("end", function(d) {
-                if (self.stopped) {
-                  d3.select(this).style("stroke", "black");
-                }
-              });
-          }
+      }
+    }
+    // accumulate the colors/directions to be used
+    for (let key in links) {
+      let congestion = self.congestion(links[key]);
+      let pathId = key.replace(/\./g, "\\.").replace(/ /g, "\\ ");
+      let path = d3.select(pathId);
+      if (path && !path.empty()) {
+        // start the path with transparent white
+        if (!path.attr("style")) {
+          path.style("stroke", "rgb(255, 255, 255)").style("opacity", 0);
         }
+        // transition to next color
+        path
+          .transition()
+          .duration(1000)
+          .style("stroke", congestion)
+          .style("opacity", 0.2)
+          .each("end", function(d) {
+            if (self.stopped) {
+              // fade to transparent
+              const p = d3.select(this);
+              p.transition()
+                .duration(100)
+                .style("opacity", 0)
+                .each("end", function() {
+                  // remove the style
+                  p.style("stroke", null).style("opacity", null);
+                });
+            }
+          });
       }
-    );
+    }
   }
   congestion(links) {
+    const max = STEPS - 1;
     let v = 0;
     for (let l = 0; l < links.length; l++) {
       let link = links[l];
       v = Math.max(
         v,
-        (3 * (link.undeliveredCount + link.unsettledCount)) / link.capacity
+        (max * (link.undeliveredCount + link.unsettledCount)) / link.capacity
       );
-      if (link.deliveriesDelayed1Sec || link.deliveriesDelayed10Sec) v = 3;
-      v = Math.min(3, v);
+      v = Math.min(max, v);
     }
     return this.fillColor(v);
   }
   fillColor(v) {
     let color = d3.scale
       .linear()
-      .domain([0, 1, 2, 3])
+      .domain([...Array(STEPS).keys()])
       .interpolate(d3.interpolateHcl)
       .range([
         d3.rgb("#999999"),
         d3.rgb("#00FF00"),
+        d3.rgb("#66CC00"),
         d3.rgb("#FFA500"),
+        d3.rgb("#FFCC00"),
         d3.rgb("#FF0000")
       ]);
-    return color(Math.max(0, Math.min(3, v)));
+    return color(Math.max(0, Math.min(STEPS - 1, v)));
   }
   remove() {
     this.stopped = true;
@@ -253,15 +300,15 @@ class Congestion extends TrafficAnimation {
       .selectAll("path.traffic")
       .classed("traffic", false);
     d3.select("#SVG_ID")
-      .selectAll("path.link")
-      .style("stroke", "black");
-    d3.select("#SVG_ID")
       .select("defs.custom-markers")
       .selectAll("marker")
       .remove();
   }
 }
 
+const colorGen = d3.scale.category10();
+const addressColors = {};
+
 /* Create animated dots moving along the links between routers
    to show message flow */
 class Dots extends TrafficAnimation {
@@ -272,24 +319,34 @@ class Dots extends TrafficAnimation {
     this.lastFlows = {}; // the number of dots animated between routers
     this.stopped = false;
     this.chordData = new ChordData(this.traffic.QDRService, true, converter); 
// gets ingressHistogram data
-    // colors
-    this.colorGen = d3.scale.category10();
-    for (let i = 0; i < 10; i++) {
-      this.colorGen(i);
+    if (Object.keys(addressColors).length === 0) {
+      // map address to {color, checked}
+      Dots.getAddressColors(this.traffic.QDRService, converter);
     }
-    this.chordData.getMatrix().then(() => {
-      const addresses = this.chordData.getAddresses();
-      const addressColors = {};
-      for (let address in addresses) {
-        this.fillColor(address, addressColors);
-      }
-      traffic.updateAddresses = this.updateAddresses;
-      this.traffic.$scope.handleUpdatedAddresses(addresses);
-      this.traffic.$scope.handleUpdateAddressColors(addressColors);
-      // set excludedAddresses
-      this.updateAddresses();
+  }
+
+  static getAddressColors(service, converter) {
+    return new Promise(resolve => {
+      const chordData = new ChordData(service, true, converter);
+      chordData.getMatrix().then(() => {
+        const addresses = chordData.getAddresses();
+        for (let address in addresses) {
+          addressColors[address] = { color: colorGen(address), checked: true };
+        }
+        resolve(addressColors);
+      });
     });
   }
+
+  setup() {
+    this.traffic.QDRService.management.topology.addUpdateEntities([
+      {
+        entity: "router.node",
+        attrs: ["id", "nextHop"]
+      }
+    ]);
+  }
+
   remove() {
     d3.select("#SVG_ID")
       .selectAll("path.traffic")
@@ -300,15 +357,13 @@ class Dots extends TrafficAnimation {
     this.lastFlows = {};
     this.stopped = true;
   }
-  updateAddresses() {
-    this.excludedAddresses = [];
-    for (const address in this.traffic.addresses) {
-      if (!this.traffic.addresses[address]) 
this.excludedAddresses.push(address);
-    }
-    if (this.chordData) {
-      this.chordData.setFilter(this.excludedAddresses);
-    }
+
+  updateAddresses(excludedAddresses) {
+    this.chordData.setFilter(excludedAddresses);
+    // make sure no excludedAddress have an animation
+    this.doUpdate();
   }
+
   fadeOtherAddresses(address) {
     d3.selectAll("circle.flow").classed("fade", function(d) {
       return d.address !== address;
@@ -317,173 +372,177 @@ class Dots extends TrafficAnimation {
   unFadeAll() {
     d3.selectAll("circle.flow").classed("fade", false);
   }
+
   doUpdate() {
-    let self = this;
     this.stopped = false;
-    // we need the nextHop data to show traffic between routers that are 
connected by intermediaries
-    this.traffic.QDRService.management.topology.ensureAllEntities(
-      [
-        {
-          entity: "router.node",
-          attrs: ["id", "nextHop"]
-        }
-      ],
-      function() {
-        // if we were stopped between the request and response, just exit
-        if (self.stopped) return;
-        // get the ingressHistogram data for all routers
-        self.chordData.getMatrix().then(self.render.bind(self), function(e) {
-          console.log("Could not get message histogram" + e);
-        });
-      }
-    );
+    // get the ingressHistogram data for all routers
+    this.chordData.getMatrix().then(this.render);
   }
-  render(matrix) {
-    if (this.stopped === false) {
-      const addresses = this.chordData.getAddresses();
-      this.traffic.$scope.handleUpdatedAddresses(addresses);
-      const addressColors = {};
-      for (let address in addresses) {
-        this.fillColor(address, addressColors);
+
+  render = matrix => {
+    if (this.stopped) return;
+    const addresses = this.chordData.getAddresses();
+    let changed = false;
+    // make sure each address has a color
+    for (let address in addresses) {
+      if (!(address in addressColors)) {
+        addressColors[address] = { color: this.fillColor(address), checked: 
true };
+        changed = true;
       }
-      this.traffic.$scope.handleUpdateAddressColors(addressColors);
-
-      // get the rate of message flow between routers
-      let hops = {}; // every hop between routers that is involved in message 
flow
-      let matrixMessages = matrix.matrixMessages();
-      // the fastest traffic rate gets 3 times as many dots as the slowest
-      let minmax = matrix.getMinMax();
-      let flowScale = d3.scale
-        .linear()
-        .domain(minmax)
-        .range([1, 1.1]);
-      // row is ingress router, col is egress router. Value at [row][col] is 
the rate
-      matrixMessages.forEach(
-        function(row, r) {
-          row.forEach(
-            function(val, c) {
-              if (val > MIN_CHORD_THRESHOLD) {
-                // translate between matrix row/col and node index
-                let f = this.nodeIndexFor(
-                  this.traffic.topology.nodes.nodes,
-                  matrix.rows[r].egress
-                );
-                let t = this.nodeIndexFor(
-                  this.traffic.topology.nodes.nodes,
-                  matrix.rows[r].ingress
-                );
-                let address = matrix.getAddress(r, c);
-                if (r !== c) {
-                  // accumulate the hops between the ingress and egress routers
-                  nextHop(
-                    this.traffic.topology.nodes.nodes[f],
-                    this.traffic.topology.nodes.nodes[t],
-                    this.traffic.topology.nodes,
-                    this.traffic.topology.links,
-                    this.traffic.QDRService.management.topology.nodeInfo(),
-                    this.traffic.topology.nodes.nodes[f],
-                    function(link, fnode, tnode) {
-                      let key = "-" + link.uid;
-                      let back = fnode.index < tnode.index;
-                      if (!hops[key]) hops[key] = [];
-                      hops[key].push({
-                        val: val,
-                        back: back,
-                        address: address
-                      });
-                    }
-                  );
-                }
-                // Find the senders connected to nodes[f] and the receivers 
connected to nodes[t]
-                // and add their links to the animation
-                this.addClients(
-                  hops,
-                  this.traffic.topology.nodes.nodes,
-                  f,
-                  val,
-                  true,
-                  address
-                );
-                this.addClients(
-                  hops,
-                  this.traffic.topology.nodes.nodes,
-                  t,
-                  val,
-                  false,
-                  address
-                );
-              }
-            }.bind(this)
+    }
+    // remove any address that no longer have traffic
+    for (let address in addressColors) {
+      if (!(address in addresses)) {
+        delete addressColors[address];
+        changed = true;
+      }
+    }
+    if (changed) {
+      this.traffic.addressesChanged();
+    }
+
+    // get the rate of message flow between routers
+    let hops = {}; // every hop between routers that is involved in message 
flow
+    let matrixMessages = matrix.matrixMessages();
+    // the fastest traffic rate gets more dots than the slowest
+    let minmax = matrix.getMinMax();
+    let flowScale = d3.scale
+      .linear()
+      .domain(minmax)
+      .range([1, 1.5]);
+    // row is ingress router, col is egress router. Value at [row][col] is the 
rate
+    matrixMessages.forEach((row, r) => {
+      row.forEach((val, c) => {
+        if (val > MIN_CHORD_THRESHOLD) {
+          // translate between matrix row/col and node index
+          let f = this.nodeIndexFor(
+            this.traffic.topology.nodes.nodes,
+            matrix.rows[r].egress
           );
-        }.bind(this)
-      );
-      // for each link between routers that has traffic, start an animation
-      let keep = {};
-      for (let id in hops) {
-        let hop = hops[id];
-        for (let h = 0; h < hop.length; h++) {
-          let ahop = hop[h];
-          let pathId = id.replace(/\./g, "\\.").replace(/ /g, "\\ ");
-          let flowId =
-            id.replace(/\./g, "").replace(/ /g, "") +
-            "-" +
-            this.addressIndex(this, ahop.address) +
-            (ahop.back ? "b" : "");
-          let path = d3.select("#path" + pathId);
-          if (!path.empty()) {
-            // start the animation. If the animation is already running, this 
will have no effect
-            this.startAnimation(path, flowId, ahop, flowScale(ahop.val));
+          let t = this.nodeIndexFor(
+            this.traffic.topology.nodes.nodes,
+            matrix.rows[r].ingress
+          );
+          let address = matrix.getAddress(r, c);
+          if (r !== c) {
+            // accumulate the hops between the ingress and egress routers
+            nextHop(
+              this.traffic.topology.nodes.nodes[f],
+              this.traffic.topology.nodes.nodes[t],
+              this.traffic.topology.nodes,
+              this.traffic.topology.links,
+              this.traffic.QDRService.management.topology.nodeInfo(),
+              this.traffic.topology.nodes.nodes[f],
+              function(link, fnode, tnode) {
+                let key = "-" + link.uid();
+                let back = fnode.index < tnode.index;
+                if (!hops[key]) hops[key] = [];
+                hops[key].push({
+                  val: val,
+                  back: back,
+                  address: address
+                });
+              }
+            );
           }
-          keep[flowId] = true;
+          // Find the senders connected to nodes[f] and the receivers 
connected to nodes[t]
+          // and add their links to the animation
+          this.addClients(hops, f, val, true, address);
+          this.addClients(hops, t, val, false, address);
+
+          const ftrue = this.addEdges(hops, f, val, true, address);
+          const ffalse = this.addEdges(hops, f, val, false, address);
+          const ttrue = this.addEdges(hops, t, val, true, address);
+          const tfalse = this.addEdges(hops, t, val, false, address);
+          [...ftrue, ...ffalse, ...ttrue, ...tfalse].forEach(eIndex => {
+            this.addClients(hops, eIndex, val, true, address);
+            this.addClients(hops, eIndex, val, false, address);
+          });
         }
-      }
-      // remove any existing animations that we don't have data for anymore
-      for (let id in this.lastFlows) {
-        if (this.lastFlows[id] && !keep[id]) {
-          this.lastFlows[id] = 0;
-          d3.select("#SVG_ID")
-            .selectAll("circle.flow" + id)
-            .remove();
+      });
+    });
+    // for each link between routers that has traffic, start an animation
+    let keep = {};
+    let offset = 0; // index of the address going in the same driection
+    let total = 0; // number of addresses going in the same direction for this 
path
+
+    for (let id in hops) {
+      let hop = hops[id];
+      const backCount = hop.filter(h => h.back).length;
+      const foreCount = hop.length - backCount;
+      let backIndex = 0; // index of address going the back direction
+      let foreIndex = 0;
+      for (let h = 0; h < hop.length; h++) {
+        let ahop = hop[h];
+        let pathId = id.replace(/\./g, "\\.").replace(/ /g, "\\ ");
+        let flowId =
+          id.replace(/\./g, "").replace(/ /g, "") +
+          "-" +
+          this.addressIndex(ahop.address) +
+          (ahop.back ? "b" : "");
+        let path = d3.select("#path" + pathId);
+        if (!path.empty()) {
+          if (ahop.back) {
+            offset = backIndex++;
+            total = backCount;
+          } else {
+            offset = foreIndex++;
+            total = foreCount;
+          }
+          // start the animation. If the animation is already running, this 
will have no effect
+          this.animateDots(path, flowId, ahop, flowScale(ahop.val), offset, 
total);
         }
+        keep[flowId] = true;
       }
     }
-  }
-  // animate the d3 selection (flow) along the given path
-  animateFlow(flow, path, count, back, rate) {
+    // remove any existing animations that we don't have data for anymore
+    for (let id in this.lastFlows) {
+      if (this.lastFlows[id] && !keep[id]) {
+        this.lastFlows[id] = 0;
+        d3.select("#SVG_ID")
+          .selectAll("circle.flow" + id)
+          .remove();
+      }
+    }
+  };
+
+  // move the dots in the selection flow along the path
+  animateFlow(flow, path, back, rate, offset, total) {
     let l = path.node().getTotalLength();
+    const count = flow.size();
+    const duration = (l * 10) / rate;
     flow
       .transition()
       .ease("easeLinear")
-      .duration((l * 10) / rate)
-      .attrTween("transform", this.translateDots(this.radius, path, count, 
back))
+      .duration(duration)
+      .attrTween("transform", this.translateDots(path, count, back, offset, 
total))
       .each("end", () => {
         if (this.stopped === false) {
-          this.animateFlow(flow, path, count, back, rate);
+          setTimeout(() => {
+            this.animateFlow(flow, path, back, rate, offset, total);
+          }, 1);
         }
       });
   }
-  // create dots along the path between routers
-  startAnimation(selection, id, hop, rate) {
-    if (selection.empty()) return;
-    this.animateDots(selection, id, hop, rate);
-  }
-  animateDots(path, id, hop, rate) {
+
+  animateDots(path, id, hop, rate, offset, total) {
     let back = hop.back,
       address = hop.address;
     // the density of dots is determined by the rate of this traffic relative 
to the other traffic
     if (!path.node().getTotalLength) return;
     let len = Math.max(Math.floor(path.node().getTotalLength() / 50), 1);
     let dots = [];
-    for (let i = 0, offset = this.addressIndex(this, address); i < len; ++i) {
+    for (let i = 0, offset = this.addressIndex(address); i < len; ++i) {
       dots[i] = {
         i: i + 10 * offset,
-        address: address
+        address
       };
     }
     // keep track of the number of dots for each link. If the length of the 
link is changed,
     // re-create the animation
-    if (!this.lastFlows[id]) this.lastFlows[id] = len;
-    else {
+    if (!this.lastFlows[id]) {
+      this.lastFlows[id] = len;
+    } else {
       if (this.lastFlows[id] !== len) {
         this.lastFlows[id] = len;
         d3.select("#SVG_ID")
@@ -502,27 +561,31 @@ class Dots extends TrafficAnimation {
       .append("circle")
       .attr("class", "flow flow" + id)
       .attr("data-testid", (d, i) => `flow${id}-${i}`)
-      .attr("fill", this.fillColor(address, this.traffic.addressColors))
+      .attr("fill", this.fillColor(address))
       .attr("r", 4);
-    this.animateFlow(circles, path, dots.length, back, rate);
+
+    // start the animation
+    if (circles.size() > 0) {
+      this.animateFlow(circles, path, back, rate, offset, total);
+    }
     flow.exit().remove();
   }
-  fillColor(n, addressColors) {
-    if (!(n in addressColors)) {
-      let ci = Object.keys(addressColors).length;
-      addressColors[n] = this.colorGen(ci);
-    }
-    return addressColors[n];
+
+  fillColor(address) {
+    return colorGen(address);
   }
+
   // find the link that carries traffic for this address
   // going to nodes[f] if sender is true
   // coming from nodes[f] if sender if false.
   // Add the link's id to the hops array
-  addClients(hops, nodes, f, val, sender, address) {
+  addClients(hops, f, val, sender, address) {
+    const nodes = this.traffic.topology.nodes.nodes;
     if (!nodes[f]) return;
     const cdir = sender ? "out" : "in";
     const uuid = nodes[f].uid();
     const key = nodes[f].key;
+    if (!this.traffic.QDRService.management.topology._nodeInfo[key]) return;
     const links = this.traffic.QDRService.management.topology._nodeInfo[key][
       "router.link"
     ];
@@ -538,7 +601,6 @@ class Dots extends TrafficAnimation {
           l[ild] === cdir
         );
       }, this);
-
       // we now have the links involved in traffic for this address that
       // ingress/egress to/from this router (f).
       // Now find the created node that each link is associated with
@@ -559,7 +621,7 @@ class Dots extends TrafficAnimation {
             hops[key].push({
               val: val,
               back: !sender,
-              address: address
+              address
             });
             return true;
           }
@@ -568,19 +630,84 @@ class Dots extends TrafficAnimation {
       }
     }
   }
-  addressIndex(vis, address) {
-    return Object.keys(vis.traffic.addresses).indexOf(address);
+
+  addEdges(hops, f, val, sender, address) {
+    const nodes = this.traffic.topology.nodes.nodes;
+    if (!nodes[f]) return;
+    const edges = [];
+    const cdir = sender ? "out" : "in";
+    const uuid = nodes[f].uid();
+    const key = nodes[f].key;
+    const links = this.traffic.QDRService.management.topology._nodeInfo[key][
+      "router.link"
+    ];
+    if (links) {
+      const ilt = links.attributeNames.indexOf("linkType");
+      const ioa = links.attributeNames.indexOf("owningAddr");
+      const ici = links.attributeNames.indexOf("connectionId");
+      const ild = links.attributeNames.indexOf("linkDir");
+      let foundLinks = links.results.filter(function(l) {
+        return (
+          (l[ilt] === "endpoint" || l[ilt] === "edge-downlink") &&
+          address === utils.addr_text(l[ioa]) &&
+          l[ild] === cdir
+        );
+      }, this);
+
+      // we now have the links involved in traffic for this address that
+      // ingress/egress to/from this router (f).
+      // Now find the edge router for the links
+      const connections = 
this.traffic.QDRService.management.topology._nodeInfo[key][
+        "connection"
+      ];
+      for (let linkIndex = 0; linkIndex < foundLinks.length; linkIndex++) {
+        const connectionId = foundLinks[linkIndex][ici];
+        const iconnid = connections.attributeNames.indexOf("identity");
+        const connection = connections.results.find(
+          result => result[iconnid] === connectionId
+        );
+        if (connection) {
+          const container = utils.valFor(
+            connections.attributeNames,
+            connection,
+            "container"
+          );
+          const edge = nodes.find(
+            node => node.nodeType === "_edge" && node.name === container
+          );
+          if (edge) {
+            const uuid2 = edge.uid();
+            const key = ["", uuid, uuid2].join("-");
+            if (!hops[key]) hops[key] = [];
+            hops[key].push({
+              val: val,
+              back: !sender,
+              address
+            });
+            edges.push(edge.index);
+          }
+        }
+      }
+    }
+    return edges;
+  }
+
+  addressIndex(address) {
+    return Object.keys(addressColors).indexOf(address);
   }
+
   // calculate the translation for each dot along the path
-  translateDots(radius, path, count, back) {
+  translateDots(path, count, back, offset, total) {
     let pnode = path.node();
     // will be called for each element in the flow selection (for each dot)
     return function(d) {
+      const off = offset / total / count;
       // will be called with t going from 0 to 1 for each dot
       return function(t) {
         // start the points at different positions depending on their value (d)
-        let tt = t * 1000;
-        let f = ((tt + (d.i * 1000) / count) % 1000) / 1000;
+        let tt = t * 1000; // total time
+        let f = ((tt + (d.i * 1000) / count) % 1000) / 1000; // fraction
+        f = (f + off) % 1;
         if (back) f = 1 - f;
         // l needs to be calculated each tick because the path's length might 
be changed during the animation
         let l = pnode.getTotalLength();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to