forked from I2P_Developers/i2p.i2p
partial impl of the gui, still a few things left to do:
- implement some validation on the state files loaded - reenable delete and updates to refresh - integrate the real chart code (currently just plain text instead of the graphs) - gui updates i wont spend more than another day on this during the testnet, but i want to get it plotting before continuing.
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="heartbeat">
|
||||
<target name="all" depends="clean, build" />
|
||||
<target name="all" depends="clean, buildGUI" />
|
||||
<target name="build" depends="builddep, jar" />
|
||||
<target name="buildGUI" depends="build, jarGUI" />
|
||||
<target name="builddep">
|
||||
<ant dir="../../../core/java/" target="build" />
|
||||
</target>
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<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" />
|
||||
</target>
|
||||
<target name="compileGUI">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac srcdir="./src" debug="true" destdir="./build/obj" classpath="../../../core/java/build/i2p.jar" />
|
||||
@@ -18,6 +24,14 @@
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="jarGUI" depends="compileGUI">
|
||||
<jar destfile="./build/heartbeatGUI.jar" basedir="./build/obj" includes="**/*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.heartbeat.gui.HeartbeatMonitor" />
|
||||
<attribute name="Class-Path" value="i2p.jar heartbeatGUI.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="javadoc">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/javadoc" />
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
@@ -85,10 +86,19 @@ public class ClientConfig {
|
||||
public ClientConfig() {
|
||||
this(null, null, null, -1, -1, -1, -1, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a dummy client config to be fetched from the specified location
|
||||
*
|
||||
*/
|
||||
public ClientConfig(String location) {
|
||||
this(null, null, location, -1, -1, -1, -1, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param peer who we will test against
|
||||
* @param us who we are
|
||||
* @param statLocation where the stat data should be stored/fetched
|
||||
* @param duration how many minutes to keep events for
|
||||
* @param statFreq how often to write out stats
|
||||
* @param sendFreq how often to send pings
|
||||
@@ -97,11 +107,11 @@ public class ClientConfig {
|
||||
* @param comment describe this test
|
||||
* @param averagePeriods list of minutes to summarize over
|
||||
*/
|
||||
public ClientConfig(Destination peer, Destination us, String statFile, int duration, int statFreq, int sendFreq,
|
||||
public ClientConfig(Destination peer, Destination us, String statLocation, int duration, int statFreq, int sendFreq,
|
||||
int sendSize, int numHops, String comment, int averagePeriods[]) {
|
||||
_peer = peer;
|
||||
_us = us;
|
||||
_statFile = statFile;
|
||||
_statFile = statLocation;
|
||||
_statDuration = duration;
|
||||
_statFrequency = statFreq;
|
||||
_sendFrequency = sendFreq;
|
||||
@@ -273,6 +283,30 @@ public class ClientConfig {
|
||||
public void setAveragePeriods(int periods[]) {
|
||||
_averagePeriods = periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we're keeping track of the average over the given time period.
|
||||
*
|
||||
* @param minutes how many minutes to monitor
|
||||
*/
|
||||
public void addAveragePeriod(int minutes) {
|
||||
if (_averagePeriods != null) {
|
||||
for (int i = 0; i < _averagePeriods.length; i++) {
|
||||
if (_averagePeriods[i] == minutes)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int numPeriods = 1;
|
||||
if (_averagePeriods != null)
|
||||
numPeriods += _averagePeriods.length;
|
||||
int periods[] = new int[numPeriods];
|
||||
if (_averagePeriods != null)
|
||||
System.arraycopy(_averagePeriods, 0, periods, 0, _averagePeriods.length);
|
||||
periods[periods.length-1] = minutes;
|
||||
Arrays.sort(periods);
|
||||
_averagePeriods = periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many hops this test engine is configured to use for its outbound and inbound tunnels
|
||||
|
@@ -103,6 +103,7 @@ public class PeerData {
|
||||
public long getSessionStart() {
|
||||
return _sessionStart;
|
||||
}
|
||||
public void setSessionStart(long when) { _sessionStart = when; }
|
||||
|
||||
/**
|
||||
* how many pings have we sent for this test?
|
||||
@@ -211,13 +212,17 @@ public class PeerData {
|
||||
data.setPongReceived(now);
|
||||
data.setPongSent(pongSent);
|
||||
data.setWasPonged(true);
|
||||
_dataPoints.put(new Long(dateSent), data);
|
||||
addDataPoint(data);
|
||||
}
|
||||
}
|
||||
_sendRate.addData(pongSent - dateSent, 0);
|
||||
_receiveRate.addData(now - pongSent, 0);
|
||||
_lifetimeReceived++;
|
||||
}
|
||||
|
||||
protected void addDataPoint(EventDataPoint data) {
|
||||
_dataPoints.put(new Long(data.getPingSent()), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* drop all datapoints outside the window we're watching, and timeout all
|
||||
|
@@ -2,6 +2,7 @@ package net.i2p.heartbeat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
@@ -17,7 +18,7 @@ import net.i2p.util.Log;
|
||||
* Actually write out the stats for peer test
|
||||
*
|
||||
*/
|
||||
class PeerDataWriter {
|
||||
public class PeerDataWriter {
|
||||
private final static Log _log = new Log(PeerDataWriter.class);
|
||||
|
||||
/**
|
||||
@@ -28,18 +29,11 @@ class PeerDataWriter {
|
||||
*/
|
||||
public boolean persist(PeerData data) {
|
||||
String filename = data.getConfig().getStatFile();
|
||||
String header = getHeader(data);
|
||||
File statFile = new File(filename);
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(statFile);
|
||||
fos.write(header.getBytes());
|
||||
fos.write("#action\tstatus\tdate and time sent \tsendMs\treplyMs\n".getBytes());
|
||||
for (Iterator iter = data.getDataPoints().iterator(); iter.hasNext();) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint) iter.next();
|
||||
String line = getEvent(point);
|
||||
fos.write(line.getBytes());
|
||||
}
|
||||
persist(data, fos);
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error persisting the peer data for "
|
||||
@@ -53,6 +47,19 @@ class PeerDataWriter {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean persist(PeerData data, OutputStream out) throws IOException {
|
||||
String header = getHeader(data);
|
||||
|
||||
out.write(header.getBytes());
|
||||
out.write("#action\tstatus\tdate and time sent \tsendMs\treplyMs\n".getBytes());
|
||||
for (Iterator iter = data.getDataPoints().iterator(); iter.hasNext();) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint) iter.next();
|
||||
String line = getEvent(point);
|
||||
out.write(line.getBytes());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getHeader(PeerData data) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
|
@@ -0,0 +1,93 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the control widgets (refresh/load/snapshot and the
|
||||
* tabbed panel with the plot config data)
|
||||
*
|
||||
*/
|
||||
class HeartbeatControlPane extends JPanel {
|
||||
private final static Log _log = new Log(HeartbeatControlPane.class);
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JTabbedPane _configPane;
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private final static Color LIGHT_BLUE = new Color(180, 180, 255);
|
||||
private final static Color BLACK = new Color(0, 0, 0);
|
||||
private Color _background = WHITE;
|
||||
private Color _foreground = BLACK;
|
||||
|
||||
public HeartbeatControlPane(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
public void addTest(PeerPlotConfig config) {
|
||||
_configPane.addTab(config.getTitle(), null, new JScrollPane(new PeerPlotConfigPane(config, this)), config.getSummary());
|
||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||
}
|
||||
public void removeTest(PeerPlotConfig config) {
|
||||
_gui.getMonitor().getState().removeTest(config);
|
||||
int index = _configPane.indexOfTab(config.getTitle());
|
||||
if (index >= 0)
|
||||
_configPane.removeTabAt(index);
|
||||
}
|
||||
|
||||
public void testsUpdated() {
|
||||
List knownNames = new ArrayList(8);
|
||||
for (int i = 0; i < _gui.getMonitor().getState().getTestCount(); i++) {
|
||||
PeerPlotState state = _gui.getMonitor().getState().getTest(i);
|
||||
String title = state.getPlotConfig().getTitle();
|
||||
knownNames.add(state.getPlotConfig().getTitle());
|
||||
if (_configPane.indexOfTab(title) >= 0) {
|
||||
_log.debug("We already know about [" + title + "]");
|
||||
} else {
|
||||
_log.info("The test [" + title + "] is new to us");
|
||||
PeerPlotConfigPane pane = new PeerPlotConfigPane(state.getPlotConfig(), this);
|
||||
_configPane.addTab(state.getPlotConfig().getTitle(), null, new JScrollPane(pane), state.getPlotConfig().getSummary());
|
||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||
}
|
||||
}
|
||||
List toRemove = new ArrayList(4);
|
||||
for (int i = 0; i < _configPane.getTabCount(); i++) {
|
||||
if (knownNames.contains(_configPane.getTitleAt(i))) {
|
||||
// noop
|
||||
} else {
|
||||
toRemove.add(_configPane.getTitleAt(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < toRemove.size(); i++) {
|
||||
String title = (String)toRemove.get(i);
|
||||
_log.info("Removing test [" + title + "]");
|
||||
_configPane.removeTabAt(_configPane.indexOfTab(title));
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
if (_gui != null)
|
||||
setBackground(_gui.getBackground());
|
||||
else
|
||||
setBackground(_background);
|
||||
setLayout(new BorderLayout());
|
||||
HeartbeatMonitorCommandBar bar = new HeartbeatMonitorCommandBar(_gui);
|
||||
bar.setBackground(getBackground());
|
||||
add(bar, BorderLayout.NORTH);
|
||||
_configPane = new JTabbedPane(JTabbedPane.LEFT);
|
||||
_configPane.setBackground(_background);
|
||||
//add(_configPane, BorderLayout.CENTER);
|
||||
add(_configPane, BorderLayout.SOUTH);
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor {
|
||||
private final static Log _log = new Log(HeartbeatMonitor.class);
|
||||
private HeartbeatMonitorState _state;
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
|
||||
public HeartbeatMonitor() { this(null); }
|
||||
public HeartbeatMonitor(String configFilename) {
|
||||
_state = new HeartbeatMonitorState(configFilename);
|
||||
_gui = new HeartbeatMonitorGUI(this);
|
||||
}
|
||||
|
||||
public void runMonitor() {
|
||||
loadConfig();
|
||||
I2PThread t = new I2PThread(new HeartbeatMonitorRunner(this));
|
||||
t.setName("HeartbeatMonitor");
|
||||
t.setDaemon(false);
|
||||
t.start();
|
||||
_log.debug("Monitor started");
|
||||
}
|
||||
|
||||
/** give us all the data/config available */
|
||||
HeartbeatMonitorState getState() { return _state; }
|
||||
|
||||
/** for all of the peer tests being monitored, refetch the data and rerender */
|
||||
void refetchData() {
|
||||
_log.debug("Refetching data");
|
||||
for (int i = 0; i < _state.getTestCount(); i++)
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, _state.getTest(i));
|
||||
}
|
||||
|
||||
/** (re)load the config defining what peer tests we are monitoring (and how to render) */
|
||||
void loadConfig() {
|
||||
//for (int i = 0; i < 10; i++) {
|
||||
// load("fake" + i);
|
||||
//}
|
||||
}
|
||||
|
||||
public void load(String location) {
|
||||
PeerPlotConfig cfg = new PeerPlotConfig(location);
|
||||
PeerPlotState state = new PeerPlotState(cfg);
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||
}
|
||||
|
||||
public synchronized void peerPlotStateFetched(PeerPlotState state) {
|
||||
_state.addTest(state);
|
||||
_gui.stateUpdated();
|
||||
}
|
||||
|
||||
/** store the config defining what peer tests we are monitoring (and how to render) */
|
||||
void storeConfig() {}
|
||||
|
||||
public static void main(String args[]) {
|
||||
Thread.currentThread().setName("HeartbeatMonitor.main");
|
||||
if (args.length == 1)
|
||||
new HeartbeatMonitor(args[0]).runMonitor();
|
||||
else
|
||||
new HeartbeatMonitor().runMonitor();
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
|
||||
class HeartbeatMonitorCommandBar extends JPanel {
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JComboBox _refreshRate;
|
||||
private JTextField _location;
|
||||
|
||||
public HeartbeatMonitorCommandBar(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
private void refreshChanged(ItemEvent evt) {}
|
||||
private void loadCalled() {
|
||||
_gui.getMonitor().load(_location.getText());
|
||||
}
|
||||
|
||||
private void browseCalled() {
|
||||
JFileChooser chooser = new JFileChooser(_location.getText());
|
||||
chooser.setBackground(_gui.getBackground());
|
||||
chooser.setMultiSelectionEnabled(false);
|
||||
int rv = chooser.showDialog(this, "Load");
|
||||
if (rv == JFileChooser.APPROVE_OPTION)
|
||||
_gui.getMonitor().load(chooser.getSelectedFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
_refreshRate = new JComboBox(new DefaultComboBoxModel(new Object[] {"10 second refresh", "30 second refresh", "1 minute refresh", "5 minute refresh"}));
|
||||
_refreshRate.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { refreshChanged(evt); } });
|
||||
_refreshRate.setEnabled(false);
|
||||
_refreshRate.setBackground(_gui.getBackground());
|
||||
add(_refreshRate);
|
||||
JLabel loadLabel = new JLabel("Load from: ");
|
||||
loadLabel.setBackground(_gui.getBackground());
|
||||
add(loadLabel);
|
||||
_location = new JTextField(20);
|
||||
_location.setToolTipText("Either specify a local filename or a fully qualified URL");
|
||||
_location.setBackground(_gui.getBackground());
|
||||
add(_location);
|
||||
JButton browse = new JButton("Browse...");
|
||||
browse.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { browseCalled(); } });
|
||||
browse.setBackground(_gui.getBackground());
|
||||
add(browse);
|
||||
JButton load = new JButton("Load");
|
||||
load.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadCalled(); } });
|
||||
load.setBackground(_gui.getBackground());
|
||||
add(load);
|
||||
setBackground(_gui.getBackground());
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
class HeartbeatMonitorGUI extends JFrame {
|
||||
private HeartbeatMonitor _monitor;
|
||||
private HeartbeatPlotPane _plotPane;
|
||||
private HeartbeatControlPane _controlPane;
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private Color _background = WHITE;
|
||||
|
||||
public HeartbeatMonitorGUI(HeartbeatMonitor monitor) {
|
||||
super("Heartbeat Monitor");
|
||||
_monitor = monitor;
|
||||
initializeComponents();
|
||||
pack();
|
||||
setResizable(false);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
HeartbeatMonitor getMonitor() { return _monitor; }
|
||||
|
||||
/** build up all our widgets */
|
||||
private void initializeComponents() {
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
setBackground(_background);
|
||||
|
||||
_plotPane = new HeartbeatPlotPane(this);
|
||||
_plotPane.setBackground(_background);
|
||||
JScrollPane pane = new JScrollPane(_plotPane);
|
||||
pane.setBackground(_background);
|
||||
getContentPane().add(pane, BorderLayout.CENTER);
|
||||
|
||||
_controlPane = new HeartbeatControlPane(this);
|
||||
_controlPane.setBackground(_background);
|
||||
getContentPane().add(_controlPane, BorderLayout.SOUTH);
|
||||
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
initializeMenus();
|
||||
}
|
||||
|
||||
public void stateUpdated() {
|
||||
_controlPane.testsUpdated();
|
||||
_plotPane.stateUpdated();
|
||||
}
|
||||
|
||||
private void exitCalled() {
|
||||
_monitor.getState().setWasKilled(true);
|
||||
setVisible(false);
|
||||
System.exit(0);
|
||||
}
|
||||
private void loadConfigCalled() {}
|
||||
private void saveConfigCalled() {}
|
||||
private void loadSnapshotCalled() {}
|
||||
private void saveSnapshotCalled() {}
|
||||
|
||||
private void initializeMenus() {
|
||||
JMenuBar bar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
JMenuItem loadConfig = new JMenuItem("Load config");
|
||||
loadConfig.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadConfigCalled(); } });
|
||||
JMenuItem saveConfig = new JMenuItem("Save config");
|
||||
saveConfig.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { saveConfigCalled(); } });
|
||||
JMenuItem saveSnapshot = new JMenuItem("Save snapshot");
|
||||
saveSnapshot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { saveSnapshotCalled(); } });
|
||||
JMenuItem loadSnapshot = new JMenuItem("Load snapshot");
|
||||
loadSnapshot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadSnapshotCalled(); } });
|
||||
JMenuItem exit = new JMenuItem("Exit");
|
||||
exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { exitCalled(); } });
|
||||
|
||||
fileMenu.add(loadConfig);
|
||||
fileMenu.add(saveConfig);
|
||||
fileMenu.add(loadSnapshot);
|
||||
fileMenu.add(saveSnapshot);
|
||||
fileMenu.add(exit);
|
||||
bar.add(fileMenu);
|
||||
setJMenuBar(bar);
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Periodically fire off necessary events (instructing the heartbeat monitor when
|
||||
* to refetch the data, etc). This is the only active thread in the heartbeat
|
||||
* monitor (outside the swing/jvm threads)
|
||||
*
|
||||
*/
|
||||
class HeartbeatMonitorRunner implements Runnable {
|
||||
private final static Log _log = new Log(HeartbeatMonitorRunner.class);
|
||||
private HeartbeatMonitor _monitor;
|
||||
|
||||
public HeartbeatMonitorRunner(HeartbeatMonitor monitor) {
|
||||
_monitor = monitor;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (!_monitor.getState().getWasKilled()) {
|
||||
_monitor.refetchData();
|
||||
try { Thread.sleep(_monitor.getState().getRefreshRateMs()); } catch (InterruptedException ie) {}
|
||||
}
|
||||
_log.info("Stopping the heartbeat monitor runner");
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* manage the current state of the GUI - all data points, as well as any
|
||||
* rendering or configuration options.
|
||||
*
|
||||
*/
|
||||
class HeartbeatMonitorState {
|
||||
private String _configFile;
|
||||
private List _peerPlotState;
|
||||
private int _currentPeerPlotConfig;
|
||||
private int _refreshRateMs;
|
||||
private boolean _killed;
|
||||
|
||||
/** by default, refresh every 30 seconds */
|
||||
private final static int DEFAULT_REFRESH_RATE = 30*1000;
|
||||
/** where do we load/store config info from? */
|
||||
private final static String DEFAULT_CONFIG_FILE = "heartbeatMonitor.config";
|
||||
|
||||
public HeartbeatMonitorState() { this(DEFAULT_CONFIG_FILE); }
|
||||
public HeartbeatMonitorState(String configFile) {
|
||||
_peerPlotState = Collections.synchronizedList(new ArrayList());
|
||||
_refreshRateMs = DEFAULT_REFRESH_RATE;
|
||||
_configFile = configFile;
|
||||
_killed = false;
|
||||
_currentPeerPlotConfig = 0;
|
||||
}
|
||||
|
||||
/** how many tests are we monitoring? */
|
||||
public int getTestCount() { return _peerPlotState.size(); }
|
||||
public PeerPlotState getTest(int peer) { return (PeerPlotState)_peerPlotState.get(peer); }
|
||||
public void addTest(PeerPlotState peerState) {
|
||||
if (!_peerPlotState.contains(peerState))
|
||||
_peerPlotState.add(peerState);
|
||||
}
|
||||
public void removeTest(PeerPlotState peerState) { _peerPlotState.remove(peerState); }
|
||||
|
||||
public void removeTest(PeerPlotConfig peerConfig) {
|
||||
for (int i = 0; i < getTestCount(); i++) {
|
||||
PeerPlotState state = getTest(i);
|
||||
if (state.getPlotConfig() == peerConfig) {
|
||||
removeTest(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** which of the tests are we currently editing/viewing? */
|
||||
public int getPeerPlotConfig() { return _currentPeerPlotConfig; }
|
||||
public void setPeerPlotConfig(int whichTest) { _currentPeerPlotConfig = whichTest; }
|
||||
|
||||
/** how frequently should we update the data? */
|
||||
public int getRefreshRateMs() { return _refreshRateMs; }
|
||||
public void setRefreshRateMs(int ms) { _refreshRateMs = ms; }
|
||||
|
||||
/** where is our config stored? */
|
||||
public String getConfigFile() { return _configFile; }
|
||||
public void setConfigFile(String filename) { _configFile = filename; }
|
||||
|
||||
/** have we been shut down? */
|
||||
public boolean getWasKilled() { return _killed; }
|
||||
public void setWasKilled(boolean killed) { _killed = killed; }
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JScrollPane;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*
|
||||
*/
|
||||
class HeartbeatPlotPane extends JPanel {
|
||||
private final static Log _log = new Log(HeartbeatPlotPane.class);
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JTextArea _text;
|
||||
|
||||
public HeartbeatPlotPane(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
public void stateUpdated() {
|
||||
StringBuffer buf = new StringBuffer(32*1024);
|
||||
PeerDataWriter writer = new PeerDataWriter();
|
||||
|
||||
for (int i = 0; i < _gui.getMonitor().getState().getTestCount(); i++) {
|
||||
StaticPeerData data = _gui.getMonitor().getState().getTest(i).getCurrentData();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
|
||||
try {
|
||||
writer.persist(data, baos);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("wtf, error writing to a byte array?", ioe);
|
||||
}
|
||||
buf.append(new String(baos.toByteArray())).append("\n\n\n");
|
||||
}
|
||||
|
||||
_text.setText(buf.toString());
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
setBackground(new Color(255, 255, 255));
|
||||
//Dimension size = new Dimension(800, 600);
|
||||
_text = new JTextArea("",30,80); // 16, 60);
|
||||
_text.setAutoscrolls(true);
|
||||
_text.setEditable(false);
|
||||
// _text.setLineWrap(true);
|
||||
// add(new JScrollPane(_text));
|
||||
add(_text);
|
||||
//add(new JScrollPane(_text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
|
||||
//setPreferredSize(size);
|
||||
}
|
||||
}
|
@@ -1,5 +1,17 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
|
||||
/**
|
||||
@@ -7,24 +19,197 @@ import net.i2p.heartbeat.ClientConfig;
|
||||
*
|
||||
*/
|
||||
class PeerPlotConfig {
|
||||
/** where can we find the current state/data (either as a filename or a URL)? */
|
||||
private String _location;
|
||||
/** what test are we defining the plot data for? */
|
||||
private ClientConfig _config;
|
||||
/** how should we render the current data set? */
|
||||
private PlotSeriesConfig _currentSeriesConfig;
|
||||
/** how should we render the various averages available? */
|
||||
private List _averageSeriesConfigs;
|
||||
private Set _listeners;
|
||||
private boolean _disabled;
|
||||
|
||||
private final static void foo() {
|
||||
// bar
|
||||
if (true) {
|
||||
// baz
|
||||
public PeerPlotConfig(String location) {
|
||||
this(location, null, null, null);
|
||||
}
|
||||
|
||||
public PeerPlotConfig(String location, ClientConfig config, PlotSeriesConfig currentSeriesConfig, List averageSeriesConfigs) {
|
||||
_location = location;
|
||||
if (config == null)
|
||||
config = new ClientConfig(location);
|
||||
_config = config;
|
||||
if (currentSeriesConfig != null)
|
||||
_currentSeriesConfig = currentSeriesConfig;
|
||||
else
|
||||
_currentSeriesConfig = new PlotSeriesConfig(0);
|
||||
|
||||
if (averageSeriesConfigs != null) {
|
||||
_averageSeriesConfigs = averageSeriesConfigs;
|
||||
} else {
|
||||
rebuildAverageSeriesConfigs();
|
||||
}
|
||||
// baf
|
||||
_listeners = Collections.synchronizedSet(new HashSet(2));
|
||||
_disabled = false;
|
||||
}
|
||||
|
||||
public void rebuildAverageSeriesConfigs() {
|
||||
int periods[] = _config.getAveragePeriods();
|
||||
if (periods == null) {
|
||||
_averageSeriesConfigs = Collections.synchronizedList(new ArrayList(0));
|
||||
} else {
|
||||
Arrays.sort(periods);
|
||||
_averageSeriesConfigs = Collections.synchronizedList(new ArrayList(periods.length));
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
_averageSeriesConfigs.add(new PlotSeriesConfig(periods[i]*60*1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addAverage(int minutes) {
|
||||
_config.addAveragePeriod(minutes);
|
||||
|
||||
TreeMap ordered = new TreeMap();
|
||||
for (int i = 0; i < _averageSeriesConfigs.size(); i++) {
|
||||
PlotSeriesConfig cfg = (PlotSeriesConfig)_averageSeriesConfigs.get(i);
|
||||
ordered.put(new Long(cfg.getPeriod()), cfg);
|
||||
}
|
||||
ordered.put(new Long(minutes*60*1000), new PlotSeriesConfig(minutes*60*1000));
|
||||
|
||||
List cfgs = Collections.synchronizedList(new ArrayList(ordered.size()));
|
||||
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); )
|
||||
cfgs.add(iter.next());
|
||||
|
||||
_averageSeriesConfigs = cfgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where is the current state data supposed to be found? This must either be a
|
||||
* local file path or a URL
|
||||
*
|
||||
*/
|
||||
public String getLocation() { return _location; }
|
||||
public void setLocation(String location) {
|
||||
_location = location;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/** What are we configuring? */
|
||||
public ClientConfig getClientConfig() { return _config; }
|
||||
public void setClientConfig(ClientConfig config) {
|
||||
_config = config;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/** How do we want to render the current data set? */
|
||||
public PlotSeriesConfig getCurrentSeriesConfig() { return _currentSeriesConfig; }
|
||||
public void setCurrentSeriesConfig(PlotSeriesConfig config) {
|
||||
_currentSeriesConfig = config;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/** How do we want to render the averages? */
|
||||
public List getAverageSeriesConfigs() { return _averageSeriesConfigs; }
|
||||
public void setAverageSeriesConfigs(List configs) { _averageSeriesConfigs = configs; }
|
||||
|
||||
/** four char description of the peer */
|
||||
public String getPeerName() {
|
||||
Destination peer = getClientConfig().getPeer();
|
||||
if (peer == null)
|
||||
return "????";
|
||||
else
|
||||
return peer.calculateHash().toBase64().substring(0, 4);
|
||||
}
|
||||
|
||||
// moo
|
||||
|
||||
private final static void biff() {
|
||||
// b0nk
|
||||
if (false) {
|
||||
// boink
|
||||
}
|
||||
// b00m
|
||||
public String getTitle() { return getPeerName() + '.' + getSize() + '.' + getClientConfig().getSendFrequency(); }
|
||||
public String getSummary() {
|
||||
return "Send peer " + getPeerName() + ' ' + getSize() + " every " +
|
||||
getClientConfig().getSendFrequency() + " seconds through " +
|
||||
getClientConfig().getNumHops() + "-hop tunnels";
|
||||
}
|
||||
|
||||
private String getSize() {
|
||||
int bytes = getClientConfig().getSendSize();
|
||||
if (bytes < 1024)
|
||||
return bytes + "b";
|
||||
else
|
||||
return bytes/1024 + "kb";
|
||||
}
|
||||
|
||||
/** we've got someone who wants to be notified of changes to the plot config */
|
||||
public void addListener(UpdateListener lsnr) { _listeners.add(lsnr); }
|
||||
public void removeListener(UpdateListener lsnr) { _listeners.remove(lsnr); }
|
||||
|
||||
void fireUpdate() {
|
||||
if (_disabled) return;
|
||||
for (Iterator iter = _listeners.iterator(); iter.hasNext(); ) {
|
||||
((UpdateListener)iter.next()).configUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void disableEvents() { _disabled = true; }
|
||||
public void enableEvents() { _disabled = false; }
|
||||
|
||||
/**
|
||||
* How do we want to render a particular dataset (either the current or the averaged values)?
|
||||
*/
|
||||
public class PlotSeriesConfig {
|
||||
private long _period;
|
||||
private boolean _plotSendTime;
|
||||
private boolean _plotReceiveTime;
|
||||
private boolean _plotLostMessages;
|
||||
private Color _plotLineColor;
|
||||
|
||||
public PlotSeriesConfig(long period) {
|
||||
this(period, false, false, false, null);
|
||||
}
|
||||
public PlotSeriesConfig(long period, boolean plotSend, boolean plotReceive, boolean plotLost, Color plotColor) {
|
||||
_period = period;
|
||||
_plotSendTime = plotSend;
|
||||
_plotReceiveTime = plotReceive;
|
||||
_plotLostMessages = plotLost;
|
||||
_plotLineColor = plotColor;
|
||||
}
|
||||
|
||||
public PeerPlotConfig getPlotConfig() { return PeerPlotConfig.this; }
|
||||
|
||||
/**
|
||||
* What period is this series config describing?
|
||||
*
|
||||
* @return 0 for current, otherwise # milliseconds that are being averaged over
|
||||
*/
|
||||
public long getPeriod() { return _period; }
|
||||
public void setPeriod(long period) {
|
||||
_period = period;
|
||||
fireUpdate();
|
||||
}
|
||||
/** Should we render the time to send (ping to peer)? */
|
||||
public boolean getPlotSendTime() { return _plotSendTime; }
|
||||
public void setPlotSendTime(boolean shouldPlot) {
|
||||
_plotSendTime = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/** Should we render the time to receive (peer pong to us)? */
|
||||
public boolean getPlotReceiveTime() { return _plotReceiveTime; }
|
||||
public void setPlotReceiveTime(boolean shouldPlot) {
|
||||
_plotReceiveTime = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/** Should we render the number of messages lost (ping sent, no pong received in time)? */
|
||||
public boolean getPlotLostMessages() { return _plotLostMessages; }
|
||||
public void setPlotLostMessages(boolean shouldPlot) {
|
||||
_plotLostMessages = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/** What color should we plot the data with? */
|
||||
public Color getPlotLineColor() { return _plotLineColor; }
|
||||
public void setPlotLineColor(Color color) {
|
||||
_plotLineColor = color;
|
||||
fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public interface UpdateListener {
|
||||
void configUpdated(PeerPlotConfig config);
|
||||
}
|
||||
// baa
|
||||
}
|
@@ -0,0 +1,339 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.border.BevelBorder;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener {
|
||||
private final static Log _log = new Log(PeerPlotConfigPane.class);
|
||||
private PeerPlotConfig _config;
|
||||
private HeartbeatControlPane _parent;
|
||||
private JLabel _title;
|
||||
private JButton _delete;
|
||||
private JLabel _fromLabel;
|
||||
private JTextField _from;
|
||||
private JTextArea _comments;
|
||||
private JLabel _peerLabel;
|
||||
private JTextField _peerKey;
|
||||
private JLabel _localLabel;
|
||||
private JTextField _localKey;
|
||||
private OptionLine _options[];
|
||||
private Random _rnd = new Random();
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private Color _background = WHITE;
|
||||
|
||||
public PeerPlotConfigPane(PeerPlotConfig config, HeartbeatControlPane pane) {
|
||||
_config = config;
|
||||
_parent = pane;
|
||||
if (_parent != null)
|
||||
_background = _parent.getBackground();
|
||||
_config.addListener(this);
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/** called when the user wants to stop monitoring this test */
|
||||
private void delete() {
|
||||
_parent.removeTest(_config);
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
buildComponents();
|
||||
placeComponents(this);
|
||||
refreshView();
|
||||
//setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
setBackground(_background);
|
||||
}
|
||||
|
||||
/** place all the gui components onto the given panel */
|
||||
private void placeComponents(JPanel body) {
|
||||
body.setLayout(new GridBagLayout());
|
||||
GridBagConstraints cts = new GridBagConstraints();
|
||||
|
||||
// row 0: title + delete
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 0;
|
||||
cts.gridwidth = 5;
|
||||
cts.anchor = GridBagConstraints.WEST;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_title, cts);
|
||||
cts.gridx = 5;
|
||||
cts.gridwidth = 1;
|
||||
cts.anchor = GridBagConstraints.NORTHWEST;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_delete, cts);
|
||||
|
||||
// row 1: from + location
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 1;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_fromLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_from, cts);
|
||||
|
||||
// row 2: comment
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 2;
|
||||
cts.gridwidth = 6;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_comments, cts);
|
||||
|
||||
// row 3: peer + peerKey
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 3;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_peerLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_peerKey, cts);
|
||||
|
||||
// row 4: local + localKey
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 4;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_localLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_localKey, cts);
|
||||
|
||||
// row 5-N: data row
|
||||
for (int i = 0; i < _options.length; i++) {
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 5 + i;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
cts.anchor = GridBagConstraints.WEST;
|
||||
if (_options[i]._durationMinutes <= 0)
|
||||
body.add(new JLabel("Data: "), cts);
|
||||
else
|
||||
body.add(new JLabel(_options[i]._durationMinutes + "m avg: "), cts);
|
||||
|
||||
cts.gridx = 1;
|
||||
body.add(_options[i]._send, cts);
|
||||
cts.gridx = 2;
|
||||
body.add(_options[i]._recv, cts);
|
||||
cts.gridx = 3;
|
||||
body.add(_options[i]._lost, cts);
|
||||
cts.gridx = 4;
|
||||
body.add(_options[i]._all, cts);
|
||||
cts.gridx = 5;
|
||||
body.add(_options[i]._color, cts);
|
||||
}
|
||||
}
|
||||
|
||||
/** build all of the gui components */
|
||||
private void buildComponents() {
|
||||
_title = new JLabel(_config.getSummary());
|
||||
_title.setBackground(_background);
|
||||
_delete = new JButton("Delete");
|
||||
_delete.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { delete(); } });
|
||||
_delete.setEnabled(false);
|
||||
_delete.setBackground(_background);
|
||||
_fromLabel = new JLabel("Location: ");
|
||||
_fromLabel.setBackground(_background);
|
||||
_from = new JTextField(_config.getLocation());
|
||||
_from.setEditable(false);
|
||||
_from.setBackground(_background);
|
||||
_comments = new JTextArea(_config.getClientConfig().getComment(), 2, 20);
|
||||
// _comments = new JTextArea(_config.getClientConfig().getComment(), 2, 40);
|
||||
_comments.setEditable(false);
|
||||
_comments.setBackground(_background);
|
||||
_peerLabel = new JLabel("Peer: ");
|
||||
_peerLabel.setBackground(_background);
|
||||
_peerKey = new JTextField(_config.getClientConfig().getPeer().toBase64(), 8);
|
||||
_peerKey.setBackground(_background);
|
||||
_localLabel = new JLabel("Local: ");
|
||||
_localLabel.setBackground(_background);
|
||||
_localKey = new JTextField(_config.getClientConfig().getUs().toBase64(), 8);
|
||||
_localKey.setBackground(_background);
|
||||
|
||||
int averagedPeriods[] = _config.getClientConfig().getAveragePeriods();
|
||||
if (averagedPeriods == null)
|
||||
averagedPeriods = new int[0];
|
||||
|
||||
_options = new OptionLine[1 + averagedPeriods.length];
|
||||
_options[0] = new OptionLine(0);
|
||||
for (int i = 0; i < averagedPeriods.length; i++) {
|
||||
_options[1+i] = new OptionLine(averagedPeriods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** the settings have changed - revise */
|
||||
private void refreshView() {
|
||||
for (int i = 0; i < _options.length; i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_options[i]._durationMinutes);
|
||||
if (cfg == null) {
|
||||
_log.warn("Config for minutes " + _options[i]._durationMinutes + " was not found?");
|
||||
continue;
|
||||
}
|
||||
_log.debug("Refreshing view for minutes ["+ _options[i]._durationMinutes + "]: send [" +
|
||||
_options[i]._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||
_options[i]._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||
_options[i]._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
||||
_options[i]._send.setSelected(cfg.getPlotSendTime());
|
||||
_options[i]._recv.setSelected(cfg.getPlotReceiveTime());
|
||||
_options[i]._lost.setSelected(cfg.getPlotLostMessages());
|
||||
if (cfg.getPlotLineColor() != null)
|
||||
_options[i]._color.setBackground(cfg.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
|
||||
/** find the right config for the given period, or null if none exist */
|
||||
private PeerPlotConfig.PlotSeriesConfig getConfig(int minutes) {
|
||||
if (minutes <= 0)
|
||||
return _config.getCurrentSeriesConfig();
|
||||
|
||||
List configs = _config.getAverageSeriesConfigs();
|
||||
for (int i = 0; i < configs.size(); i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
||||
if (cfg.getPeriod() == minutes * 60*1000)
|
||||
return cfg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** notified that the config has been updated */
|
||||
public void configUpdated(PeerPlotConfig config) { refreshView(); }
|
||||
|
||||
private class ChooseColor implements ActionListener {
|
||||
private int _minutes;
|
||||
private JButton _button;
|
||||
|
||||
public ChooseColor(int minutes, JButton button) {
|
||||
_minutes = minutes;
|
||||
_button = button;
|
||||
}
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
||||
Color origColor = null;
|
||||
if (cfg != null)
|
||||
origColor = cfg.getPlotLineColor();
|
||||
Color color = JColorChooser.showDialog(PeerPlotConfigPane.this, "What color should this line be?", origColor);
|
||||
if (color != null) {
|
||||
if (cfg != null)
|
||||
cfg.setPlotLineColor(color);
|
||||
_button.setBackground(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OptionLine {
|
||||
int _durationMinutes;
|
||||
JCheckBox _send;
|
||||
JCheckBox _recv;
|
||||
JCheckBox _lost;
|
||||
JCheckBox _all;
|
||||
JButton _color;
|
||||
|
||||
public OptionLine(int durationMinutes) {
|
||||
_durationMinutes = durationMinutes;
|
||||
_send = new JCheckBox("send time");
|
||||
_send.setBackground(_background);
|
||||
_recv = new JCheckBox("receive time");
|
||||
_recv.setBackground(_background);
|
||||
_lost = new JCheckBox("lost messages");
|
||||
_lost.setBackground(_background);
|
||||
_all = new JCheckBox("all");
|
||||
_all.setBackground(_background);
|
||||
_color = new JButton("color");
|
||||
int r = _rnd.nextInt(255);
|
||||
if (r < 0) r = -r;
|
||||
int g = _rnd.nextInt(255);
|
||||
if (g < 0) g = -g;
|
||||
int b = _rnd.nextInt(255);
|
||||
if (b < 0) b = -b;
|
||||
_color.setBackground(new Color(r, g, b));
|
||||
|
||||
_send.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_recv.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_lost.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_all.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_color.addActionListener(new ChooseColor(durationMinutes, _color));
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateListener implements ActionListener {
|
||||
private OptionLine _line;
|
||||
private int _minutes;
|
||||
public UpdateListener(OptionLine line, int minutes) {
|
||||
_line = line;
|
||||
_minutes = minutes;
|
||||
}
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
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();
|
||||
_log.debug("Updating data for minutes ["+ _line._durationMinutes + "]: send [" +
|
||||
_line._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||
_line._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||
_line._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
||||
|
||||
boolean force = _line._all.isSelected();
|
||||
cfg.setPlotSendTime(_line._send.isSelected() || force);
|
||||
cfg.setPlotReceiveTime(_line._recv.isSelected() || force);
|
||||
cfg.setPlotLostMessages(_line._lost.isSelected() || force);
|
||||
cfg.getPlotConfig().enableEvents();
|
||||
cfg.getPlotConfig().fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public final static void main(String args[]) {
|
||||
Test t = new Test();
|
||||
t.runTest();
|
||||
}
|
||||
|
||||
private final static class Test implements PeerPlotStateFetcher.FetchStateReceptor {
|
||||
public void runTest() {
|
||||
PeerPlotConfig cfg = new PeerPlotConfig("C:\\testnet\\r2\\heartbeatStat_10s_30kb.txt");
|
||||
PeerPlotState state = new PeerPlotState(cfg);
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
public void peerPlotStateFetched(PeerPlotState state) {
|
||||
javax.swing.JFrame f = new javax.swing.JFrame("Test");
|
||||
f.getContentPane().add(new JScrollPane(new PeerPlotConfigPane(state.getPlotConfig(), null)));
|
||||
f.pack();
|
||||
f.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
|
||||
/**
|
||||
* Current data + plot config for a particular test
|
||||
*
|
||||
*/
|
||||
class PeerPlotState {
|
||||
private StaticPeerData _currentData;
|
||||
private PeerPlotConfig _plotConfig;
|
||||
|
||||
public PeerPlotState() {
|
||||
this(null, null);
|
||||
}
|
||||
public PeerPlotState(PeerPlotConfig config) {
|
||||
this(config, new StaticPeerData(config.getClientConfig()));
|
||||
}
|
||||
public PeerPlotState(PeerPlotConfig config, StaticPeerData data) {
|
||||
_plotConfig = config;
|
||||
_currentData = data;
|
||||
}
|
||||
|
||||
public void addAverage(int minutes, int sendMs, int recvMs, int lost) {
|
||||
// make sure we've got the config entry for the average
|
||||
_plotConfig.addAverage(minutes);
|
||||
// add the data point...
|
||||
_currentData.addAverage(minutes, sendMs, recvMs, lost);
|
||||
}
|
||||
|
||||
/**
|
||||
* we successfully got a ping/pong through
|
||||
*
|
||||
* @param sendTime when did the ping get sent?
|
||||
* @param sendMs how much later did the peer receive the ping?
|
||||
* @param recvMs how much later than that did we receive the pong?
|
||||
*/
|
||||
public void addSuccess(long sendTime, int sendMs, int recvMs) {
|
||||
_currentData.addData(sendTime, sendMs, recvMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* we lost a ping/pong
|
||||
*
|
||||
* @param sendTime when did we send the ping?
|
||||
*/
|
||||
public void addLost(long sendTime) {
|
||||
_currentData.addData(sendTime);
|
||||
}
|
||||
|
||||
/** data set to render */
|
||||
public StaticPeerData getCurrentData() { return _currentData; }
|
||||
public void setCurrentData(StaticPeerData data) { _currentData = data; }
|
||||
|
||||
/** configuration options on how to render the data set */
|
||||
public PeerPlotConfig getPlotConfig() { return _plotConfig; }
|
||||
public void setPlotConfig(PeerPlotConfig config) { _plotConfig = config; }
|
||||
}
|
@@ -0,0 +1,350 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.DataFormatException;
|
||||
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.FileInputStream;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
class PeerPlotStateFetcher {
|
||||
private final static Log _log = new Log(PeerPlotStateFetcher.class);
|
||||
|
||||
/**
|
||||
* Fetch and fill the specified state structure
|
||||
*
|
||||
*/
|
||||
public static void fetchPeerPlotState(FetchStateReceptor receptor, PeerPlotState state) {
|
||||
I2PThread t = new I2PThread(new Fetcher(receptor, state));
|
||||
t.setDaemon(true);
|
||||
t.setName("Fetch state from " + state.getPlotConfig().getLocation());
|
||||
t.start();
|
||||
}
|
||||
|
||||
public interface FetchStateReceptor {
|
||||
void peerPlotStateFetched(PeerPlotState state);
|
||||
}
|
||||
|
||||
private static class Fetcher implements Runnable {
|
||||
private PeerPlotState _state;
|
||||
private FetchStateReceptor _receptor;
|
||||
public Fetcher(FetchStateReceptor receptor, PeerPlotState state) {
|
||||
_state = state;
|
||||
_receptor = receptor;
|
||||
}
|
||||
public void run() {
|
||||
String loc = _state.getPlotConfig().getLocation();
|
||||
_log.debug("Load called [" + loc + "]");
|
||||
InputStream in = null;
|
||||
try {
|
||||
try {
|
||||
URL location = new URL(loc);
|
||||
in = location.openStream();
|
||||
} catch (MalformedURLException mue) {
|
||||
_log.debug("Not a url [" + loc + "]");
|
||||
in = null;
|
||||
}
|
||||
|
||||
if (in == null)
|
||||
in = new FileInputStream(loc);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
handleLine(line);
|
||||
}
|
||||
|
||||
if (valid())
|
||||
_receptor.peerPlotStateFetched(_state);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error retrieving from the location [" + loc + "]", ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check to make sure we've got everything we need
|
||||
*
|
||||
*/
|
||||
boolean valid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle a line from the data set - these can be formatted in one of the
|
||||
* following ways. <p />
|
||||
*
|
||||
* <pre>
|
||||
* peer khWYqCETu9YtPUvGV92ocsbEW5DezhKlIG7ci8RLX3g=
|
||||
* local u-9hlR1ik2hemXf0HvKMfeRgrS86CbNQh25e7XBhaQE=
|
||||
* peerDest [base 64 of the full destination]
|
||||
* localDest [base 64 of the full destination]
|
||||
* numTunnelHops 2
|
||||
* comment Test with localhost sending 30KB every 20 seconds
|
||||
* sendFrequency 20
|
||||
* sendSize 30720
|
||||
* sessionStart 20040409.22:51:10.915
|
||||
* currentTime 20040409.23:31:39.607
|
||||
* numPending 2
|
||||
* lifetimeSent 118
|
||||
* lifetimeRecv 113
|
||||
* #averages minutes sendMs recvMs numLost
|
||||
* periodAverage 1 1843 771 0
|
||||
* periodAverage 5 786 752 1
|
||||
* periodAverage 30 855 735 3
|
||||
* #action status date and time sent sendMs replyMs
|
||||
* EVENT OK 20040409.23:21:44.742 691 670
|
||||
* EVENT OK 20040409.23:22:05.201 671 581
|
||||
* EVENT OK 20040409.23:22:26.301 1182 1452
|
||||
* EVENT OK 20040409.23:22:47.322 24304 1723
|
||||
* EVENT OK 20040409.23:23:08.232 2293 1081
|
||||
* EVENT OK 20040409.23:23:29.332 1392 641
|
||||
* EVENT OK 20040409.23:23:50.262 641 761
|
||||
* EVENT OK 20040409.23:24:11.102 651 701
|
||||
* EVENT OK 20040409.23:24:31.401 841 621
|
||||
* EVENT OK 20040409.23:24:52.061 651 681
|
||||
* EVENT OK 20040409.23:25:12.480 701 1623
|
||||
* EVENT OK 20040409.23:25:32.990 1442 1212
|
||||
* EVENT OK 20040409.23:25:54.230 591 631
|
||||
* EVENT OK 20040409.23:26:14.620 620 691
|
||||
* EVENT OK 20040409.23:26:35.199 1793 1432
|
||||
* EVENT OK 20040409.23:26:56.570 661 641
|
||||
* EVENT OK 20040409.23:27:17.200 641 660
|
||||
* EVENT OK 20040409.23:27:38.120 611 921
|
||||
* EVENT OK 20040409.23:27:58.699 831 621
|
||||
* EVENT OK 20040409.23:28:19.559 801 661
|
||||
* EVENT OK 20040409.23:28:40.279 601 611
|
||||
* EVENT OK 20040409.23:29:00.648 601 621
|
||||
* EVENT OK 20040409.23:29:21.288 701 661
|
||||
* EVENT LOST 20040409.23:29:41.828
|
||||
* EVENT LOST 20040409.23:30:02.327
|
||||
* EVENT LOST 20040409.23:30:22.656
|
||||
* EVENT OK 20040409.23:31:24.305 1843 771
|
||||
* </pre>
|
||||
*/
|
||||
private void handleLine(String line) {
|
||||
if (line.startsWith("peerDest"))
|
||||
handlePeerDest(line);
|
||||
else if (line.startsWith("localDest"))
|
||||
handleLocalDest(line);
|
||||
else if (line.startsWith("numTunnelHops"))
|
||||
handleNumTunnelHops(line);
|
||||
else if (line.startsWith("comment"))
|
||||
handleComment(line);
|
||||
else if (line.startsWith("sendFrequency"))
|
||||
handleSendFrequency(line);
|
||||
else if (line.startsWith("sendSize"))
|
||||
handleSendSize(line);
|
||||
else if (line.startsWith("periodAverage"))
|
||||
handlePeriodAverage(line);
|
||||
else if (line.startsWith("EVENT"))
|
||||
handleEvent(line);
|
||||
else if (line.startsWith("numPending"))
|
||||
handleNumPending(line);
|
||||
else if (line.startsWith("sessionStart"))
|
||||
handleSessionStart(line);
|
||||
else
|
||||
_log.debug("Not handled: " + line);
|
||||
}
|
||||
|
||||
private void handlePeerDest(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String destKey = tok.nextToken();
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(destKey);
|
||||
_state.getPlotConfig().getClientConfig().setPeer(d);
|
||||
_log.debug("Setting the peer to " + d.calculateHash().toBase64());
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Unable to parse the peerDest line: [" + line + "]", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLocalDest(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String destKey = tok.nextToken();
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(destKey);
|
||||
_state.getPlotConfig().getClientConfig().setUs(d);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Unable to parse the localDest line: [" + line + "]", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleComment(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
StringBuffer buf = new StringBuffer(line.length()-32);
|
||||
while (tok.hasMoreTokens())
|
||||
buf.append(tok.nextToken()).append(' ');
|
||||
_state.getPlotConfig().getClientConfig().setComment(buf.toString());
|
||||
}
|
||||
|
||||
private void handleNumTunnelHops(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setNumHops(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the numTunnelHops line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNumPending(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getCurrentData().setPendingCount(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the numPending line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendFrequency(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setSendFrequency(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendFrequency line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendSize(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setSendSize(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendSize line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSessionStart(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String date = tok.nextToken();
|
||||
try {
|
||||
long when = getDate(date);
|
||||
_state.getCurrentData().setSessionStart(when);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sessionStart line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePeriodAverage(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
try {
|
||||
// periodAverage minutes sendMs recvMs numLost
|
||||
int min = Integer.parseInt(tok.nextToken());
|
||||
int send = Integer.parseInt(tok.nextToken());
|
||||
int recv = Integer.parseInt(tok.nextToken());
|
||||
int lost = Integer.parseInt(tok.nextToken());
|
||||
_state.addAverage(min, send, recv, lost);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendSize line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEvent(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
|
||||
// * EVENT OK 20040409.23:29:21.288 701 661
|
||||
// * EVENT LOST 20040409.23:29:41.828
|
||||
tok.nextToken(); // ignore first two
|
||||
tok.nextToken();
|
||||
try {
|
||||
long when = getDate(tok.nextToken());
|
||||
if (when < 0) {
|
||||
_log.error("Invalid EVENT line: [" + line + "]");
|
||||
return;
|
||||
}
|
||||
if (tok.hasMoreTokens()) {
|
||||
int sendMs = Integer.parseInt(tok.nextToken());
|
||||
int recvMs = Integer.parseInt(tok.nextToken());
|
||||
_state.addSuccess(when, sendMs, recvMs);
|
||||
} else {
|
||||
_state.addLost(when);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the EVENT line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd.HH:mm:ss.SSS", Locale.UK);
|
||||
private long getDate(String date) {
|
||||
synchronized (_fmt) {
|
||||
try {
|
||||
return _fmt.parse(date).getTime();
|
||||
} catch (ParseException pe) {
|
||||
_log.error("Unable to parse the date [" + date + "]", pe);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fakeRun() {
|
||||
try {
|
||||
Destination peer = new Destination();
|
||||
Destination us = new Destination();
|
||||
peer.fromBase64("3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJ" +
|
||||
"cS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7g" +
|
||||
"fqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teM" +
|
||||
"d5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA");
|
||||
us.fromBase64("W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYpp" +
|
||||
"K9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63" +
|
||||
"rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HC" +
|
||||
"VilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA");
|
||||
_state.getPlotConfig().getClientConfig().setPeer(peer);
|
||||
_state.getPlotConfig().getClientConfig().setUs(us);
|
||||
_state.getPlotConfig().getClientConfig().setNumHops(2);
|
||||
_state.getPlotConfig().getClientConfig().setComment("we do stuff\nreally nifty stuff. really");
|
||||
_state.getPlotConfig().getClientConfig().setAveragePeriods(new int[] { 1, 5, 30, 60 });
|
||||
int rnd = new java.util.Random().nextInt();
|
||||
if (rnd > 0)
|
||||
rnd = rnd % 10;
|
||||
else
|
||||
rnd = (-rnd) % 10;
|
||||
_state.getPlotConfig().getClientConfig().setSendFrequency(rnd);
|
||||
_state.getPlotConfig().getClientConfig().setSendSize(16*1024);
|
||||
_state.getPlotConfig().getClientConfig().setStatDuration(10);
|
||||
_state.getPlotConfig().rebuildAverageSeriesConfigs();
|
||||
_state.setCurrentData(new StaticPeerData(_state.getPlotConfig().getClientConfig()));
|
||||
|
||||
_receptor.peerPlotStateFetched(_state);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Raw data points for a test
|
||||
*
|
||||
*/
|
||||
class StaticPeerData extends PeerData {
|
||||
private int _pending;
|
||||
/** Integer (period, in minutes) to Integer (milliseconds) for sending a ping */
|
||||
private Map _averageSendTimes;
|
||||
/** Integer (period, in minutes) to Integer (milliseconds) for receiving a pong */
|
||||
private Map _averageReceiveTimes;
|
||||
/** Integer (period, in minutes) to Integer (num messages) of how many messages were lost on average */
|
||||
private Map _lostMessages;
|
||||
|
||||
public StaticPeerData(ClientConfig config) {
|
||||
super(config);
|
||||
_averageSendTimes = new HashMap(4);
|
||||
_averageReceiveTimes = new HashMap(4);
|
||||
_lostMessages = new HashMap(4);
|
||||
}
|
||||
|
||||
|
||||
public void addAverage(int minutes, int sendMs, int recvMs, int lost) {
|
||||
_averageSendTimes.put(new Integer(minutes), new Integer(sendMs));
|
||||
_averageReceiveTimes.put(new Integer(minutes), new Integer(recvMs));
|
||||
_lostMessages.put(new Integer(minutes), new Integer(lost));
|
||||
}
|
||||
|
||||
public void setPendingCount(int numPending) { _pending = numPending; }
|
||||
public void setSessionStart(long when) { super.setSessionStart(when); }
|
||||
|
||||
public void addData(long sendTime, int sendMs, int recvMs) {
|
||||
PeerData.EventDataPoint dataPoint = new PeerData.EventDataPoint(sendTime);
|
||||
dataPoint.setPongSent(sendTime + sendMs);
|
||||
dataPoint.setPongReceived(sendTime + sendMs + recvMs);
|
||||
dataPoint.setWasPonged(true);
|
||||
addDataPoint(dataPoint);
|
||||
}
|
||||
|
||||
public void addData(long sendTime) {
|
||||
PeerData.EventDataPoint dataPoint = new PeerData.EventDataPoint(sendTime);
|
||||
dataPoint.setWasPonged(false);
|
||||
addDataPoint(dataPoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* how many pings are still outstanding?
|
||||
* @return the number of pings outstanding
|
||||
*/
|
||||
public int getPendingCount() { return _pending; }
|
||||
|
||||
|
||||
/**
|
||||
* average time to send over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageSendTime(int period) {
|
||||
return ((Integer)_averageSendTimes.get(new Integer(period))).doubleValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* average time to receive over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageReceiveTime(int period) {
|
||||
return ((Integer)_averageReceiveTimes.get(new Integer(period))).doubleValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* number of lost messages over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return number of lost messages in the period, or -1 if we dont track that period
|
||||
*/
|
||||
public double getLostMessages(int period) {
|
||||
return ((Integer)_lostMessages.get(new Integer(period))).doubleValue();
|
||||
}
|
||||
|
||||
public void cleanup() {}
|
||||
}
|
Reference in New Issue
Block a user