the heartbeat engine and gui are good 'nuff for now
(while i want to spend another few days on it, there are more pressing things and this will meet my needs for testnet). the engine works as before, and the gui now actually plots out and follows the chart over time. The gui does have a lot of things left to be done before it can be adopted by joe sixpack - * load/store the URLs being monitored so you don't have to reenter them on each startup * clear out the x axis on refetch (now it just keeps growing, which is good and bad) * adjustable refresh rate * implement snapshots (saving all the current state files to a dir, and allowing that dir to be loaded all at once) * beautification (override the colors, etc) the net.i2p.heartbeat.** code is all public domain, BUT net.i2p.heartbeat.gui.JFreeChart* classes depend on the LGPL'ed jfreechart code, which in turn depends on apache licensed code (log4j). for the time being, this code doesn't include the jfreechart code (and dependencies), but the ant task in apps/heartbeat/java 'fetchJfreechart' downloads it and places it under apps/heartbeat/java/lib, after which you can build the GUI by running the ant task 'buildGUI' (buildGUI / etc are NOT in the standard build process). once we figure out all the details to comply with the requirements of log4j's license we'll do so. but for now, the above works.
This commit is contained in:
@ -1,20 +1,37 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project basedir="." default="all" name="heartbeat">
|
<project basedir="." default="all" name="heartbeat">
|
||||||
<target name="all" depends="clean, buildGUI" />
|
<target name="all" depends="clean, buildGUI" />
|
||||||
<target name="build" depends="builddep, jar" />
|
<target name="build" depends="builddep, jar">
|
||||||
<target name="buildGUI" depends="build, jarGUI" />
|
<echo message="heartbeat engine built, but to get the heartbeat GUI, run the buildGUI target" />
|
||||||
|
<echo message="However, to build the GUI, you need to fetch it the JFreeChart package by running the fetchJfreechart target" />
|
||||||
|
</target>
|
||||||
|
<target name="fetchJfreechart">
|
||||||
|
<mkdir dir="./lib" />
|
||||||
|
<get src="http://www.jfree.org/jfreechart/jfreechart-0.9.17.zip" dest="lib/jfreechart-0.9.17.zip" />
|
||||||
|
<unzip src="lib/jfreechart-0.9.17.zip" dest="lib/" />
|
||||||
|
</target>
|
||||||
|
<target name="buildGUI" depends="build, jfreechart, jarGUI" />
|
||||||
<target name="builddep">
|
<target name="builddep">
|
||||||
<ant dir="../../../core/java/" target="build" />
|
<ant dir="../../../core/java/" target="build" />
|
||||||
</target>
|
</target>
|
||||||
<target name="compile">
|
<target name="compile">
|
||||||
<mkdir dir="./build" />
|
<mkdir dir="./build" />
|
||||||
<mkdir dir="./build/obj" />
|
<mkdir dir="./build/obj" />
|
||||||
<javac srcdir="./src" debug="true" destdir="./build/obj" excludes="src/net/i2p/heartbeat/gui/**/*.java" classpath="../../../core/java/build/i2p.jar" />
|
<javac srcdir="./src" debug="true" destdir="./build/obj" includes="**/*.java" excludes="net/i2p/heartbeat/gui/**" classpath="../../../core/java/build/i2p.jar" />
|
||||||
</target>
|
</target>
|
||||||
<target name="compileGUI">
|
<target name="compileGUI">
|
||||||
<mkdir dir="./build" />
|
<mkdir dir="./build" />
|
||||||
<mkdir dir="./build/obj" />
|
<mkdir dir="./build/obj" />
|
||||||
<javac srcdir="./src" debug="true" destdir="./build/obj" classpath="../../../core/java/build/i2p.jar" />
|
<javac debug="true" destdir="./build/obj">
|
||||||
|
<src path="src/" />
|
||||||
|
<classpath path="../../../core/java/build/i2p.jar" />
|
||||||
|
<classpath path="lib/jfreechart-0.9.17/lib/jcommon-0.9.2.jar" />
|
||||||
|
<classpath path="lib/jfreechart-0.9.17/lib/log4j-1.2.8.jar" />
|
||||||
|
<classpath path="lib/jfreechart-0.9.17/jfreechart-0.9.17.jar" />
|
||||||
|
</javac>
|
||||||
|
</target>
|
||||||
|
<target name="jfreechart">
|
||||||
|
<ant dir="./lib/jfreechart-0.9.17/" antfile="ant/build.xml" target="compile" />
|
||||||
</target>
|
</target>
|
||||||
<target name="jar" depends="compile">
|
<target name="jar" depends="compile">
|
||||||
<jar destfile="./build/heartbeat.jar" basedir="./build/obj" includes="**/*.class">
|
<jar destfile="./build/heartbeat.jar" basedir="./build/obj" includes="**/*.class">
|
||||||
@ -25,12 +42,16 @@
|
|||||||
</jar>
|
</jar>
|
||||||
</target>
|
</target>
|
||||||
<target name="jarGUI" depends="compileGUI">
|
<target name="jarGUI" depends="compileGUI">
|
||||||
<jar destfile="./build/heartbeatGUI.jar" basedir="./build/obj" includes="**/*.class">
|
<copy file="lib/jfreechart-0.9.17/jfreechart-0.9.17.jar" todir="build/" />
|
||||||
|
<copy file="lib/jfreechart-0.9.17/lib/log4j-1.2.8.jar" todir="build/" />
|
||||||
|
<copy file="lib/jfreechart-0.9.17/lib/jcommon-0.9.2.jar" todir="build/" />
|
||||||
|
<jar destfile="./build/heartbeatGUI.jar" basedir="./build/obj" includes="**">
|
||||||
<manifest>
|
<manifest>
|
||||||
<attribute name="Main-Class" value="net.i2p.heartbeat.gui.HeartbeatMonitor" />
|
<attribute name="Main-Class" value="net.i2p.heartbeat.gui.HeartbeatMonitor" />
|
||||||
<attribute name="Class-Path" value="i2p.jar heartbeatGUI.jar" />
|
<attribute name="Class-Path" value="log4j-1.2.8.jar jcommon-0.9.2.jar jfreechart-0.9.17.jar heartbeatGUI.jar i2p.jar" />
|
||||||
</manifest>
|
</manifest>
|
||||||
</jar>
|
</jar>
|
||||||
|
<echo message="You will need to copy the log4j, jcommon, and jfreechart jar files from build/ into your lib dir" />
|
||||||
</target>
|
</target>
|
||||||
<target name="javadoc">
|
<target name="javadoc">
|
||||||
<mkdir dir="./build" />
|
<mkdir dir="./build" />
|
||||||
@ -48,6 +69,7 @@
|
|||||||
</target>
|
</target>
|
||||||
<target name="cleandep" depends="clean">
|
<target name="cleandep" depends="clean">
|
||||||
<ant dir="../../../core/java/" target="cleandep" />
|
<ant dir="../../../core/java/" target="cleandep" />
|
||||||
|
<ant dir="../../../core/java/" target="cleandep" />
|
||||||
</target>
|
</target>
|
||||||
<target name="distclean" depends="clean">
|
<target name="distclean" depends="clean">
|
||||||
<ant dir="../../../core/java/" target="distclean" />
|
<ant dir="../../../core/java/" target="distclean" />
|
||||||
|
@ -4,6 +4,7 @@ import net.i2p.data.Destination;
|
|||||||
import net.i2p.util.Clock;
|
import net.i2p.util.Clock;
|
||||||
import net.i2p.util.I2PThread;
|
import net.i2p.util.I2PThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.Clock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for actually conducting the tests, coordinating the storing of the
|
* Responsible for actually conducting the tests, coordinating the storing of the
|
||||||
|
@ -30,6 +30,8 @@ import net.i2p.util.Log;
|
|||||||
* # where our private destination keys are located - if this doesn't exist,
|
* # where our private destination keys are located - if this doesn't exist,
|
||||||
* # a new one will be created and saved there (by default, heartbeat.keys)
|
* # a new one will be created and saved there (by default, heartbeat.keys)
|
||||||
* privateDestinationFile=heartbeat_r2.keys
|
* privateDestinationFile=heartbeat_r2.keys
|
||||||
|
* # where do we want to export the plain base64 of our destination?
|
||||||
|
* publicDestinationFile=heartbeat_r2.txt
|
||||||
*
|
*
|
||||||
* ## peer tests configured below:
|
* ## peer tests configured below:
|
||||||
*
|
*
|
||||||
|
@ -37,6 +37,8 @@ class I2PAdapter {
|
|||||||
private int _numHops;
|
private int _numHops;
|
||||||
/** filename containing the heartbeat engine's private destination info */
|
/** filename containing the heartbeat engine's private destination info */
|
||||||
private String _privateDestFile;
|
private String _privateDestFile;
|
||||||
|
/** filename to store the heartbeat engine's public destination in base64*/
|
||||||
|
private String _publicDestFile;
|
||||||
/** our destination */
|
/** our destination */
|
||||||
private Destination _localDest;
|
private Destination _localDest;
|
||||||
/** who do we tell? */
|
/** who do we tell? */
|
||||||
@ -53,6 +55,10 @@ class I2PAdapter {
|
|||||||
private static final String DEST_FILE_PROP = "privateDestinationFile";
|
private static final String DEST_FILE_PROP = "privateDestinationFile";
|
||||||
/** by default, the private destination data is in "heartbeat.keys" */
|
/** by default, the private destination data is in "heartbeat.keys" */
|
||||||
private static final String DEST_FILE_DEFAULT = "heartbeat.keys";
|
private static final String DEST_FILE_DEFAULT = "heartbeat.keys";
|
||||||
|
/** where will we export the public destination in base 64? */
|
||||||
|
private static final String PUBLIC_DEST_FILE_PROP = "publicDestinationFile";
|
||||||
|
/** where will we export the public destination in base 64? */
|
||||||
|
private static final String PUBLIC_DEST_FILE_DEFAULT = "heartbeat.txt";
|
||||||
/** This config property defines where the I2P router is */
|
/** This config property defines where the I2P router is */
|
||||||
private static final String I2CP_HOST_PROP = "i2cpHost";
|
private static final String I2CP_HOST_PROP = "i2cpHost";
|
||||||
/** by default, the I2P host is "localhost" */
|
/** by default, the I2P host is "localhost" */
|
||||||
@ -72,6 +78,7 @@ class I2PAdapter {
|
|||||||
*/
|
*/
|
||||||
public I2PAdapter() {
|
public I2PAdapter() {
|
||||||
_privateDestFile = null;
|
_privateDestFile = null;
|
||||||
|
_publicDestFile = null;
|
||||||
_i2cpHost = null;
|
_i2cpHost = null;
|
||||||
_i2cpPort = -1;
|
_i2cpPort = -1;
|
||||||
_localDest = null;
|
_localDest = null;
|
||||||
@ -126,6 +133,7 @@ class I2PAdapter {
|
|||||||
*/
|
*/
|
||||||
void loadConfig(Properties props) {
|
void loadConfig(Properties props) {
|
||||||
String privDestFile = props.getProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
String privDestFile = props.getProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
||||||
|
String pubDestFile = props.getProperty(PUBLIC_DEST_FILE_PROP, PUBLIC_DEST_FILE_DEFAULT);
|
||||||
String host = props.getProperty(I2CP_HOST_PROP, I2CP_HOST_DEFAULT);
|
String host = props.getProperty(I2CP_HOST_PROP, I2CP_HOST_DEFAULT);
|
||||||
String port = props.getProperty(I2CP_PORT_PROP, "" + I2CP_PORT_DEFAULT);
|
String port = props.getProperty(I2CP_PORT_PROP, "" + I2CP_PORT_DEFAULT);
|
||||||
String numHops = props.getProperty(NUMHOPS_PROP, "" + NUMHOPS_DEFAULT);
|
String numHops = props.getProperty(NUMHOPS_PROP, "" + NUMHOPS_DEFAULT);
|
||||||
@ -151,6 +159,7 @@ class I2PAdapter {
|
|||||||
|
|
||||||
_numHops = hops;
|
_numHops = hops;
|
||||||
_privateDestFile = privDestFile;
|
_privateDestFile = privDestFile;
|
||||||
|
_publicDestFile = pubDestFile;
|
||||||
_i2cpHost = host;
|
_i2cpHost = host;
|
||||||
_i2cpPort = portNum;
|
_i2cpPort = portNum;
|
||||||
}
|
}
|
||||||
@ -166,6 +175,12 @@ class I2PAdapter {
|
|||||||
props.setProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
props.setProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_publicDestFile != null) {
|
||||||
|
props.setProperty(PUBLIC_DEST_FILE_PROP, _publicDestFile);
|
||||||
|
} else {
|
||||||
|
props.setProperty(PUBLIC_DEST_FILE_PROP, PUBLIC_DEST_FILE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
if (_i2cpHost != null) {
|
if (_i2cpHost != null) {
|
||||||
props.setProperty(I2CP_HOST_PROP, _i2cpHost);
|
props.setProperty(I2CP_HOST_PROP, _i2cpHost);
|
||||||
} else {
|
} else {
|
||||||
@ -406,6 +421,18 @@ class I2PAdapter {
|
|||||||
if (_log.shouldLog(Log.INFO)) {
|
if (_log.shouldLog(Log.INFO)) {
|
||||||
_log.info("Existing destination loaded: [" + us.toBase64() + "]");
|
_log.info("Existing destination loaded: [" + us.toBase64() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream(_publicDestFile);
|
||||||
|
fos.write(us.toBase64().getBytes());
|
||||||
|
fos.flush();
|
||||||
|
} catch (IOException fioe) {
|
||||||
|
_log.error("Error writing out the plain destination to [" + _publicDestFile + "]", fioe);
|
||||||
|
} finally {
|
||||||
|
if (fos != null) try { fos.close(); } catch (IOException fioe) {}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
if (fin != null) try {
|
if (fin != null) try {
|
||||||
fin.close();
|
fin.close();
|
||||||
@ -466,7 +493,9 @@ class I2PAdapter {
|
|||||||
*/
|
*/
|
||||||
private Properties getOptions() {
|
private Properties getOptions() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
|
// this should be BEST_EFFORT, but i'm too lazy to update the code to handle tracking
|
||||||
|
// sessionTags and sessionKeys, marking them as delivered on pong.
|
||||||
|
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
|
||||||
props.setProperty(I2PClient.PROP_TCP_HOST, _i2cpHost);
|
props.setProperty(I2PClient.PROP_TCP_HOST, _i2cpHost);
|
||||||
props.setProperty(I2PClient.PROP_TCP_PORT, _i2cpPort + "");
|
props.setProperty(I2PClient.PROP_TCP_PORT, _i2cpPort + "");
|
||||||
props.setProperty("tunnels.depthInbound", "" + _numHops);
|
props.setProperty("tunnels.depthInbound", "" + _numHops);
|
||||||
|
@ -43,6 +43,7 @@ class HeartbeatControlPane extends JPanel {
|
|||||||
_configPane.addTab(config.getTitle(), null, new JScrollPane(new PeerPlotConfigPane(config, this)), config.getSummary());
|
_configPane.addTab(config.getTitle(), null, new JScrollPane(new PeerPlotConfigPane(config, this)), config.getSummary());
|
||||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||||
|
_gui.pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,14 +6,16 @@ import net.i2p.util.Log;
|
|||||||
/**
|
/**
|
||||||
* The HeartbeatMonitor, complete with main()! Act now, and it's only 5 easy
|
* The HeartbeatMonitor, complete with main()! Act now, and it's only 5 easy
|
||||||
* payments of $19.95 (plus shipping and handling)! You heard me, only _5_
|
* payments of $19.95 (plus shipping and handling)! You heard me, only _5_
|
||||||
* easy payments of $19.95 (plus shipping and handling)!
|
* easy payments of $19.95 (plus shipping and handling)! <p />
|
||||||
*
|
*
|
||||||
* (fine print: something about some states in the US requiring the addition
|
* (fine print: something about some states in the US requiring the addition
|
||||||
* of sales tax... or something)
|
* of sales tax... or something) <p />
|
||||||
*
|
*
|
||||||
* (finer print: Satan owns you. Deal with it.)
|
* (finer print: Satan owns you. Deal with it.) <p />
|
||||||
|
*
|
||||||
|
* (even finer print: usage: <code>HeartbeatMonitor [configFilename]</code>)
|
||||||
*/
|
*/
|
||||||
public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor {
|
public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor, PeerPlotConfig.UpdateListener {
|
||||||
private final static Log _log = new Log(HeartbeatMonitor.class);
|
private final static Log _log = new Log(HeartbeatMonitor.class);
|
||||||
private HeartbeatMonitorState _state;
|
private HeartbeatMonitorState _state;
|
||||||
private HeartbeatMonitorGUI _gui;
|
private HeartbeatMonitorGUI _gui;
|
||||||
@ -73,6 +75,7 @@ public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor
|
|||||||
*/
|
*/
|
||||||
public void load(String location) {
|
public void load(String location) {
|
||||||
PeerPlotConfig cfg = new PeerPlotConfig(location);
|
PeerPlotConfig cfg = new PeerPlotConfig(location);
|
||||||
|
cfg.addListener(this);
|
||||||
PeerPlotState state = new PeerPlotState(cfg);
|
PeerPlotState state = new PeerPlotState(cfg);
|
||||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||||
}
|
}
|
||||||
@ -99,4 +102,9 @@ public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor
|
|||||||
else
|
else
|
||||||
new HeartbeatMonitor().runMonitor();
|
new HeartbeatMonitor().runMonitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void configUpdated(PeerPlotConfig config) {
|
||||||
|
_log.debug("Config updated, revamping the gui");
|
||||||
|
_gui.stateUpdated();
|
||||||
|
}
|
||||||
}
|
}
|
@ -46,7 +46,7 @@ class HeartbeatMonitorCommandBar extends JPanel {
|
|||||||
_refreshRate.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { refreshChanged(evt); } });
|
_refreshRate.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { refreshChanged(evt); } });
|
||||||
_refreshRate.setEnabled(false);
|
_refreshRate.setEnabled(false);
|
||||||
_refreshRate.setBackground(_gui.getBackground());
|
_refreshRate.setBackground(_gui.getBackground());
|
||||||
add(_refreshRate);
|
//add(_refreshRate);
|
||||||
JLabel loadLabel = new JLabel("Load from: ");
|
JLabel loadLabel = new JLabel("Load from: ");
|
||||||
loadLabel.setBackground(_gui.getBackground());
|
loadLabel.setBackground(_gui.getBackground());
|
||||||
add(loadLabel);
|
add(loadLabel);
|
||||||
|
@ -10,6 +10,7 @@ import javax.swing.JMenu;
|
|||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
|
|
||||||
class HeartbeatMonitorGUI extends JFrame {
|
class HeartbeatMonitorGUI extends JFrame {
|
||||||
private HeartbeatMonitor _monitor;
|
private HeartbeatMonitor _monitor;
|
||||||
@ -27,7 +28,7 @@ class HeartbeatMonitorGUI extends JFrame {
|
|||||||
_monitor = monitor;
|
_monitor = monitor;
|
||||||
initializeComponents();
|
initializeComponents();
|
||||||
pack();
|
pack();
|
||||||
setResizable(false);
|
//setResizable(false);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,16 +40,18 @@ class HeartbeatMonitorGUI extends JFrame {
|
|||||||
|
|
||||||
setBackground(_background);
|
setBackground(_background);
|
||||||
|
|
||||||
_plotPane = new HeartbeatPlotPane(this);
|
_plotPane = new JFreeChartHeartbeatPlotPane(this); // new HeartbeatPlotPane(this);
|
||||||
_plotPane.setBackground(_background);
|
_plotPane.setBackground(_background);
|
||||||
JScrollPane pane = new JScrollPane(_plotPane);
|
//JScrollPane pane = new JScrollPane(_plotPane);
|
||||||
pane.setBackground(_background);
|
//pane.setBackground(_background);
|
||||||
getContentPane().add(pane, BorderLayout.CENTER);
|
getContentPane().add(new JScrollPane(_plotPane), BorderLayout.CENTER);
|
||||||
|
|
||||||
_controlPane = new HeartbeatControlPane(this);
|
_controlPane = new HeartbeatControlPane(this);
|
||||||
_controlPane.setBackground(_background);
|
_controlPane.setBackground(_background);
|
||||||
getContentPane().add(_controlPane, BorderLayout.SOUTH);
|
getContentPane().add(_controlPane, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
//JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(_plotPane), new JScrollPane(_controlPane));
|
||||||
|
//getContentPane().add(pane, BorderLayout.CENTER);
|
||||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
initializeMenus();
|
initializeMenus();
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
class HeartbeatPlotPane extends JPanel {
|
class HeartbeatPlotPane extends JPanel {
|
||||||
private final static Log _log = new Log(HeartbeatPlotPane.class);
|
private final static Log _log = new Log(HeartbeatPlotPane.class);
|
||||||
private HeartbeatMonitorGUI _gui;
|
protected HeartbeatMonitorGUI _gui;
|
||||||
private JTextArea _text;
|
private JTextArea _text;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,9 +48,9 @@ class HeartbeatPlotPane extends JPanel {
|
|||||||
_text.setText(buf.toString());
|
_text.setText(buf.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeComponents() {
|
protected void initializeComponents() {
|
||||||
setBackground(new Color(255, 255, 255));
|
setBackground(_gui.getBackground());
|
||||||
// Dimension size = new Dimension(800, 600);
|
//Dimension size = new Dimension(800, 600);
|
||||||
_text = new JTextArea("",30,80); // 16, 60);
|
_text = new JTextArea("",30,80); // 16, 60);
|
||||||
_text.setAutoscrolls(true);
|
_text.setAutoscrolls(true);
|
||||||
_text.setEditable(false);
|
_text.setEditable(false);
|
||||||
|
@ -0,0 +1,234 @@
|
|||||||
|
package net.i2p.heartbeat.gui;
|
||||||
|
|
||||||
|
import net.i2p.heartbeat.PeerData;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
|
import org.jfree.data.XYSeries;
|
||||||
|
import org.jfree.data.XYSeriesCollection;
|
||||||
|
import org.jfree.data.MovingAverage;
|
||||||
|
import org.jfree.chart.JFreeChart;
|
||||||
|
import org.jfree.chart.ChartPanel;
|
||||||
|
import org.jfree.chart.plot.Plot;
|
||||||
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.chart.axis.DateAxis;
|
||||||
|
import org.jfree.chart.axis.NumberAxis;
|
||||||
|
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||||
|
import org.jfree.chart.renderer.XYItemRenderer;
|
||||||
|
import org.jfree.chart.renderer.XYDotRenderer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
class JFreeChartAdapter {
|
||||||
|
private final static Log _log = new Log(JFreeChartAdapter.class);
|
||||||
|
private final static Color WHITE = new Color(255, 255, 255);
|
||||||
|
|
||||||
|
ChartPanel createPanel(HeartbeatMonitorState state) {
|
||||||
|
ChartPanel panel = new ChartPanel(createChart(state));
|
||||||
|
panel.setDisplayToolTips(true);
|
||||||
|
panel.setEnforceFileExtensions(true);
|
||||||
|
panel.setHorizontalZoom(true);
|
||||||
|
panel.setVerticalZoom(true);
|
||||||
|
panel.setMouseZoomable(true, true);
|
||||||
|
panel.getChart().setBackgroundPaint(WHITE);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
JFreeChart createChart(HeartbeatMonitorState state) {
|
||||||
|
Plot plot = createPlot(state);
|
||||||
|
JFreeChart chart = new JFreeChart("I2P Heartbeat performance", Font.getFont("arial"), plot, true);
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateChart(ChartPanel panel, HeartbeatMonitorState state) {
|
||||||
|
XYPlot plot = (XYPlot)panel.getChart().getPlot();
|
||||||
|
plot.setDataset(getCollection(state));
|
||||||
|
updateLines(plot, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getFirst(HeartbeatMonitorState state) {
|
||||||
|
long first = -1;
|
||||||
|
for (int i = 0; i < state.getTestCount(); i++) {
|
||||||
|
List dataPoints = state.getTest(i).getCurrentData().getDataPoints();
|
||||||
|
if ( (dataPoints != null) && (dataPoints.size() > 0) ) {
|
||||||
|
PeerData.EventDataPoint data = (PeerData.EventDataPoint)dataPoints.get(0);
|
||||||
|
if ( (first < 0) || (first > data.getPingSent()) )
|
||||||
|
first = data.getPingSent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plot createPlot(HeartbeatMonitorState state) {
|
||||||
|
XYItemRenderer renderer = new XYLineAndShapeRenderer(); // new XYDotRenderer(); //
|
||||||
|
XYPlot plot = new XYPlot(getCollection(state), new DateAxis(), new NumberAxis("ms"), renderer);
|
||||||
|
updateLines(plot, state);
|
||||||
|
return plot;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLines(XYPlot plot, HeartbeatMonitorState state) {
|
||||||
|
if (true) return;
|
||||||
|
if (state == null) return;
|
||||||
|
for (int i = 0; i < state.getTestCount(); i++) {
|
||||||
|
PeerPlotConfig config = state.getTest(i).getPlotConfig();
|
||||||
|
PeerPlotConfig.PlotSeriesConfig curConfig = config.getCurrentSeriesConfig();
|
||||||
|
XYSeriesCollection col = ((XYSeriesCollection)plot.getDataset());
|
||||||
|
for (int j = 0; j < col.getSeriesCount(); j++) {
|
||||||
|
//XYItemRenderer renderer = plot.getRendererForDataset(col.getSeries(j));
|
||||||
|
XYItemRenderer renderer = plot.getRendererForDataset(col);
|
||||||
|
if (col.getSeriesName(j).startsWith(config.getTitle() + " send")) {
|
||||||
|
if (curConfig.getPlotSendTime()) {
|
||||||
|
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (col.getSeriesName(j).startsWith(config.getTitle() + " receive")) {
|
||||||
|
if (curConfig.getPlotReceiveTime()) {
|
||||||
|
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (col.getSeriesName(j).startsWith(config.getTitle() + " lost")) {
|
||||||
|
if (curConfig.getPlotLostMessages()) {
|
||||||
|
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XYSeriesCollection getCollection(HeartbeatMonitorState state) {
|
||||||
|
XYSeriesCollection col = new XYSeriesCollection();
|
||||||
|
if (state != null) {
|
||||||
|
for (int i = 0; i < state.getTestCount(); i++) {
|
||||||
|
addTest(col, state.getTest(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
XYSeries series = new XYSeries("latency", false, false);
|
||||||
|
series.add(System.currentTimeMillis(), 0);
|
||||||
|
col.addSeries(series);
|
||||||
|
}
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTest(XYSeriesCollection col, PeerPlotState state) {
|
||||||
|
PeerPlotConfig config = state.getPlotConfig();
|
||||||
|
PeerPlotConfig.PlotSeriesConfig curConfig = config.getCurrentSeriesConfig();
|
||||||
|
addLines(col, curConfig, config.getTitle(), state.getCurrentData().getDataPoints());
|
||||||
|
addAverageLines(col, config, config.getTitle(), state.getCurrentData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param config preferences for how to display this test
|
||||||
|
* @param lineName minimal name of the test (e.g. "jxHa.32KB.60s")
|
||||||
|
* @param data List of PeerData.EventDataPoint describing all of the events in the test
|
||||||
|
*/
|
||||||
|
void addLines(XYSeriesCollection col, PeerPlotConfig.PlotSeriesConfig config, String lineName, List data) {
|
||||||
|
if (config.getPlotSendTime()) {
|
||||||
|
XYSeries sendSeries = getSendSeries(data);
|
||||||
|
sendSeries.setName(lineName + " send");
|
||||||
|
sendSeries.setDescription("milliseconds for the ping to reach the peer");
|
||||||
|
col.addSeries(sendSeries);
|
||||||
|
}
|
||||||
|
if (config.getPlotReceiveTime()) {
|
||||||
|
XYSeries recvSeries = getReceiveSeries(data);
|
||||||
|
recvSeries.setName(lineName + " receive");
|
||||||
|
recvSeries.setDescription("milliseconds for the peer's pong to reach the sender");
|
||||||
|
col.addSeries(recvSeries);
|
||||||
|
}
|
||||||
|
if (config.getPlotLostMessages()) {
|
||||||
|
XYSeries lostSeries = getLostSeries(data);
|
||||||
|
lostSeries.setName(lineName + " lost");
|
||||||
|
lostSeries.setDescription("number of ping/pong messages lost");
|
||||||
|
col.addSeries(lostSeries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a data series for each average that we're configured to render
|
||||||
|
*
|
||||||
|
* @param config preferences for how to display this test
|
||||||
|
* @param lineName minimal name of the test (e.g. "jxHa.32KB.60s")
|
||||||
|
* @param data List of PeerData.EventDataPoint describing all of the events in the test
|
||||||
|
*/
|
||||||
|
void addAverageLines(XYSeriesCollection col, PeerPlotConfig config, String lineName, StaticPeerData data) {
|
||||||
|
if (data.getDataPointCount() <= 0) return;
|
||||||
|
PeerData.EventDataPoint start = (PeerData.EventDataPoint)data.getDataPoints().get(0);
|
||||||
|
PeerData.EventDataPoint finish = (PeerData.EventDataPoint)data.getDataPoints().get(data.getDataPointCount()-1);
|
||||||
|
|
||||||
|
List configs = config.getAverageSeriesConfigs();
|
||||||
|
|
||||||
|
for (int i = 0; i < configs.size(); i++) {
|
||||||
|
PeerPlotConfig.PlotSeriesConfig cfg = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
||||||
|
int minutes = (int)cfg.getPeriod()/(60*1000);
|
||||||
|
if (cfg.getPlotSendTime()) {
|
||||||
|
double time = data.getAverageSendTime(minutes);
|
||||||
|
if (time > 0) {
|
||||||
|
XYSeries series = new XYSeries(lineName + " send " + minutes + "m avg [" + time + "]", false, false);
|
||||||
|
series.add(start.getPingSent(), time);
|
||||||
|
series.add(finish.getPingSent(), time);
|
||||||
|
series.setDescription("send time, averaged over the last " + minutes + " minutes");
|
||||||
|
col.addSeries(series);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cfg.getPlotReceiveTime()) {
|
||||||
|
double time = data.getAverageReceiveTime(minutes);
|
||||||
|
if (time > 0) {
|
||||||
|
XYSeries series = new XYSeries(lineName + " receive " + minutes + "m avg[" + time + "]", false, false);
|
||||||
|
series.add(start.getPingSent(), time);
|
||||||
|
series.add(finish.getPingSent(), time);
|
||||||
|
series.setDescription("receive time, averaged over the last " + minutes + " minutes");
|
||||||
|
col.addSeries(series);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cfg.getPlotLostMessages()) {
|
||||||
|
double num = data.getLostMessages(minutes);
|
||||||
|
if (num > 0) {
|
||||||
|
XYSeries series = new XYSeries(lineName + " lost messages (" + num + " in " + minutes + "m)", false, false);
|
||||||
|
series.add(start.getPingSent(), num);
|
||||||
|
series.add(finish.getPingSent(), num);
|
||||||
|
series.setDescription("number of messages lost in the last " + minutes + " minutes");
|
||||||
|
col.addSeries(series);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XYSeries getSendSeries(List data) {
|
||||||
|
XYSeries series = new XYSeries("sent", false, false);
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||||
|
if (point.getWasPonged()) {
|
||||||
|
series.add(point.getPingSent(), point.getPongSent()-point.getPingSent());
|
||||||
|
} else {
|
||||||
|
// series.add(data.getPingSent(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
XYSeries getReceiveSeries(List data) {
|
||||||
|
XYSeries series = new XYSeries("receive", false, false);
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||||
|
if (point.getWasPonged()) {
|
||||||
|
series.add(point.getPingSent(), point.getPongReceived()-point.getPongSent());
|
||||||
|
} else {
|
||||||
|
// series.add(data.getPingSent(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
XYSeries getLostSeries(List data) {
|
||||||
|
XYSeries series = new XYSeries("lost", false, false);
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||||
|
if (point.getWasPonged()) {
|
||||||
|
//series.add(point.getPingSent(), 0);
|
||||||
|
} else {
|
||||||
|
series.add(point.getPingSent(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package net.i2p.heartbeat.gui;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JTextArea;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import net.i2p.heartbeat.PeerDataWriter;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
|
import org.jfree.chart.ChartPanel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the graph and legend
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JFreeChartHeartbeatPlotPane extends HeartbeatPlotPane {
|
||||||
|
private final static Log _log = new Log(JFreeChartHeartbeatPlotPane.class);
|
||||||
|
private ChartPanel _panel;
|
||||||
|
private JFreeChartAdapter _adapter;
|
||||||
|
|
||||||
|
public JFreeChartHeartbeatPlotPane(HeartbeatMonitorGUI gui) {
|
||||||
|
super(gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stateUpdated() {
|
||||||
|
if (_panel == null) {
|
||||||
|
remove(0); // remove the dummy
|
||||||
|
|
||||||
|
_adapter = new JFreeChartAdapter();
|
||||||
|
_panel = _adapter.createPanel(_gui.getMonitor().getState());
|
||||||
|
_panel.setBackground(_gui.getBackground());
|
||||||
|
add(new JScrollPane(_panel), BorderLayout.CENTER);
|
||||||
|
_gui.pack();
|
||||||
|
} else {
|
||||||
|
_adapter.updateChart(_panel, _gui.getMonitor().getState());
|
||||||
|
//_gui.pack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initializeComponents() {
|
||||||
|
// noop
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
add(new JLabel(), BorderLayout.CENTER);
|
||||||
|
//dummy.setBackground(_gui.getBackground());
|
||||||
|
//dummy.setPreferredSize(new Dimension(800,600));
|
||||||
|
//add(dummy);
|
||||||
|
|
||||||
|
//add(_panel);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -11,12 +11,14 @@ import java.util.Set;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
|
import net.i2p.util.Log;
|
||||||
import net.i2p.heartbeat.ClientConfig;
|
import net.i2p.heartbeat.ClientConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure how we want to render a particular clientConfig in the GUI
|
* Configure how we want to render a particular clientConfig in the GUI
|
||||||
*/
|
*/
|
||||||
class PeerPlotConfig {
|
class PeerPlotConfig {
|
||||||
|
private final static Log _log = new Log(PeerPlotConfig.class);
|
||||||
/** where can we find the current state/data (either as a filename or a URL)? */
|
/** where can we find the current state/data (either as a filename or a URL)? */
|
||||||
private String _location;
|
private String _location;
|
||||||
/** what test are we defining the plot data for? */
|
/** what test are we defining the plot data for? */
|
||||||
@ -90,7 +92,9 @@ class PeerPlotConfig {
|
|||||||
PlotSeriesConfig cfg = (PlotSeriesConfig)_averageSeriesConfigs.get(i);
|
PlotSeriesConfig cfg = (PlotSeriesConfig)_averageSeriesConfigs.get(i);
|
||||||
ordered.put(new Long(cfg.getPeriod()), cfg);
|
ordered.put(new Long(cfg.getPeriod()), cfg);
|
||||||
}
|
}
|
||||||
ordered.put(new Long(minutes*60*1000), new PlotSeriesConfig(minutes*60*1000));
|
Long period = new Long(minutes*60*1000);
|
||||||
|
if (!ordered.containsKey(period))
|
||||||
|
ordered.put(period, new PlotSeriesConfig(minutes*60*1000));
|
||||||
|
|
||||||
List cfgs = Collections.synchronizedList(new ArrayList(ordered.size()));
|
List cfgs = Collections.synchronizedList(new ArrayList(ordered.size()));
|
||||||
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); )
|
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); )
|
||||||
@ -244,6 +248,11 @@ class PeerPlotConfig {
|
|||||||
*/
|
*/
|
||||||
public PlotSeriesConfig(long period) {
|
public PlotSeriesConfig(long period) {
|
||||||
this(period, false, false, false, null);
|
this(period, false, false, false, null);
|
||||||
|
if (period <= 0) {
|
||||||
|
_plotSendTime = true;
|
||||||
|
_plotReceiveTime = true;
|
||||||
|
_plotLostMessages = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,10 +195,10 @@ class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener
|
|||||||
_log.warn("Config for minutes " + _options[i]._durationMinutes + " was not found?");
|
_log.warn("Config for minutes " + _options[i]._durationMinutes + " was not found?");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_log.debug("Refreshing view for minutes ["+ _options[i]._durationMinutes + "]: send [" +
|
//_log.debug("Refreshing view for minutes ["+ _options[i]._durationMinutes + "]: send [" +
|
||||||
_options[i]._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
// _options[i]._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||||
_options[i]._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
// _options[i]._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||||
_options[i]._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
// _options[i]._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
||||||
_options[i]._send.setSelected(cfg.getPlotSendTime());
|
_options[i]._send.setSelected(cfg.getPlotSendTime());
|
||||||
_options[i]._recv.setSelected(cfg.getPlotReceiveTime());
|
_options[i]._recv.setSelected(cfg.getPlotReceiveTime());
|
||||||
_options[i]._lost.setSelected(cfg.getPlotLostMessages());
|
_options[i]._lost.setSelected(cfg.getPlotLostMessages());
|
||||||
@ -289,13 +289,15 @@ class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener
|
|||||||
if (g < 0) g = -g;
|
if (g < 0) g = -g;
|
||||||
int b = _rnd.nextInt(255);
|
int b = _rnd.nextInt(255);
|
||||||
if (b < 0) b = -b;
|
if (b < 0) b = -b;
|
||||||
_color.setBackground(new Color(r, g, b));
|
//_color.setBackground(new Color(r, g, b));
|
||||||
|
_color.setBackground(_background);
|
||||||
|
|
||||||
_send.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
_send.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||||
_recv.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
_recv.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||||
_lost.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
_lost.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||||
_all.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
_all.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||||
_color.addActionListener(new ChooseColor(durationMinutes, _color));
|
_color.addActionListener(new ChooseColor(durationMinutes, _color));
|
||||||
|
_color.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,22 +320,12 @@ class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener
|
|||||||
*/
|
*/
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(ActionEvent evt) {
|
||||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
||||||
if (cfg == null) {
|
|
||||||
_log.error("wtf, why is there no config for " + _minutes + "?");
|
|
||||||
|
|
||||||
List configs = _config.getAverageSeriesConfigs();
|
|
||||||
for (int i = 0; i < configs.size(); i++) {
|
|
||||||
PeerPlotConfig.PlotSeriesConfig conf = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
|
||||||
_log.debug("We know about " + conf.getPeriod());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.getPlotConfig().disableEvents();
|
cfg.getPlotConfig().disableEvents();
|
||||||
_log.debug("Updating data for minutes ["+ _line._durationMinutes + "]: send [" +
|
_log.debug("Updating data for minutes ["+ _line._durationMinutes + "]: send [" +
|
||||||
_line._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
_line._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||||
_line._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
_line._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||||
_line._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
_line._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]: config = " + cfg);
|
||||||
|
|
||||||
boolean force = _line._all.isSelected();
|
boolean force = _line._all.isSelected();
|
||||||
cfg.setPlotSendTime(_line._send.isSelected() || force);
|
cfg.setPlotSendTime(_line._send.isSelected() || force);
|
||||||
|
@ -91,7 +91,11 @@ class StaticPeerData extends PeerData {
|
|||||||
* @return milliseconds average, or -1 if we dont track that period
|
* @return milliseconds average, or -1 if we dont track that period
|
||||||
*/
|
*/
|
||||||
public double getAverageSendTime(int period) {
|
public double getAverageSendTime(int period) {
|
||||||
return ((Integer)_averageSendTimes.get(new Integer(period))).doubleValue();
|
Integer i = (Integer)_averageSendTimes.get(new Integer(period));
|
||||||
|
if (i == null)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return i.doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -102,7 +106,11 @@ class StaticPeerData extends PeerData {
|
|||||||
* @return milliseconds average, or -1 if we dont track that period
|
* @return milliseconds average, or -1 if we dont track that period
|
||||||
*/
|
*/
|
||||||
public double getAverageReceiveTime(int period) {
|
public double getAverageReceiveTime(int period) {
|
||||||
return ((Integer)_averageReceiveTimes.get(new Integer(period))).doubleValue();
|
Integer i = (Integer)_averageReceiveTimes.get(new Integer(period));
|
||||||
|
if (i == null)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return i.doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,7 +120,11 @@ class StaticPeerData extends PeerData {
|
|||||||
* @return number of lost messages in the period, or -1 if we dont track that period
|
* @return number of lost messages in the period, or -1 if we dont track that period
|
||||||
*/
|
*/
|
||||||
public double getLostMessages(int period) {
|
public double getLostMessages(int period) {
|
||||||
return ((Integer)_lostMessages.get(new Integer(period))).doubleValue();
|
Integer i = (Integer)_lostMessages.get(new Integer(period));
|
||||||
|
if (i == null)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return i.doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
Reference in New Issue
Block a user