forked from I2P_Developers/i2p.i2p
Sybil: Refactoring part 5
Make Analysis class singleton, hang off ClientAppManager prep for offline scheduling
This commit is contained in:
@ -11,6 +11,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.i2p.app.ClientAppManager;
|
||||||
|
import net.i2p.app.ClientAppState;
|
||||||
|
import static net.i2p.app.ClientAppState.*;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
@ -20,6 +23,7 @@ import net.i2p.data.router.RouterInfo;
|
|||||||
import net.i2p.data.router.RouterKeyGenerator;
|
import net.i2p.data.router.RouterKeyGenerator;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.TunnelPoolSettings;
|
import net.i2p.router.TunnelPoolSettings;
|
||||||
|
import net.i2p.router.app.RouterApp;
|
||||||
import net.i2p.router.crypto.FamilyKeyCrypto;
|
import net.i2p.router.crypto.FamilyKeyCrypto;
|
||||||
import net.i2p.router.peermanager.DBHistory;
|
import net.i2p.router.peermanager.DBHistory;
|
||||||
import net.i2p.router.peermanager.PeerProfile;
|
import net.i2p.router.peermanager.PeerProfile;
|
||||||
@ -36,10 +40,20 @@ import net.i2p.util.ObjectCounter;
|
|||||||
* @since 0.9.38 split out from SybilRenderer
|
* @since 0.9.38 split out from SybilRenderer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Analysis {
|
public class Analysis implements RouterApp {
|
||||||
|
|
||||||
private final RouterContext _context;
|
private final RouterContext _context;
|
||||||
|
private final ClientAppManager _cmgr;
|
||||||
|
private final PersistSybil _persister;
|
||||||
|
private volatile ClientAppState _state = UNINITIALIZED;
|
||||||
private final DecimalFormat fmt = new DecimalFormat("#0.00");
|
private final DecimalFormat fmt = new DecimalFormat("#0.00");
|
||||||
|
/**
|
||||||
|
* The name we register with the ClientAppManager
|
||||||
|
*/
|
||||||
|
public static final String APP_NAME = "sybil";
|
||||||
|
public static final String PROP_FREQUENCY = "router.sybilFrequency";
|
||||||
|
private static final long MIN_FREQUENCY = 60*60*1000L;
|
||||||
|
private static final long MIN_UPTIME = 75*60*1000L;
|
||||||
|
|
||||||
public static final int PAIRMAX = 20;
|
public static final int PAIRMAX = 20;
|
||||||
public static final int MAX = 10;
|
public static final int MAX = 10;
|
||||||
@ -64,8 +78,88 @@ public class Analysis {
|
|||||||
private static final double POINTS_NEW = 4.0;
|
private static final double POINTS_NEW = 4.0;
|
||||||
private static final double POINTS_BANLIST = 25.0;
|
private static final double POINTS_BANLIST = 25.0;
|
||||||
|
|
||||||
public Analysis(RouterContext ctx) {
|
/** Get via getInstance() */
|
||||||
|
private Analysis(RouterContext ctx, ClientAppManager mgr, String[] args) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
|
_cmgr = mgr;
|
||||||
|
_persister = new PersistSybil(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return non-null, creates new if not already registered
|
||||||
|
*/
|
||||||
|
public synchronized static Analysis getInstance(RouterContext ctx) {
|
||||||
|
ClientAppManager cmgr = ctx.clientAppManager();
|
||||||
|
if (cmgr == null)
|
||||||
|
return null;
|
||||||
|
Analysis rv = (Analysis) cmgr.getRegisteredApp(APP_NAME);
|
||||||
|
if (rv == null) {
|
||||||
|
rv = new Analysis(ctx, cmgr, null);
|
||||||
|
rv.startup();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PersistSybil getPersister() { return _persister; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp interface
|
||||||
|
*/
|
||||||
|
public synchronized void startup() {
|
||||||
|
changeState(STARTING);
|
||||||
|
changeState(RUNNING);
|
||||||
|
_cmgr.register(this);
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp interface
|
||||||
|
* @param args ignored
|
||||||
|
*/
|
||||||
|
public synchronized void shutdown(String[] args) {
|
||||||
|
if (_state == STOPPED)
|
||||||
|
return;
|
||||||
|
changeState(STOPPING);
|
||||||
|
changeState(STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientAppState getState() {
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return APP_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "Sybil Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/////// end ClientApp methods
|
||||||
|
|
||||||
|
private synchronized void changeState(ClientAppState state) {
|
||||||
|
_state = state;
|
||||||
|
if (_cmgr != null)
|
||||||
|
_cmgr.notify(this, state, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void schedule() {
|
||||||
|
long freq = _context.getProperty(PROP_FREQUENCY, 0L);
|
||||||
|
if (freq > 0) {
|
||||||
|
List<Long> previous = _persister.load();
|
||||||
|
long now = _context.clock().now();
|
||||||
|
long when;
|
||||||
|
if (!previous.isEmpty()) {
|
||||||
|
if (freq < MIN_FREQUENCY)
|
||||||
|
freq = MIN_FREQUENCY;
|
||||||
|
when = Math.max(previous.get(0).longValue() + freq, now);
|
||||||
|
} else {
|
||||||
|
when = now;
|
||||||
|
}
|
||||||
|
long up = _context.router().getUptime();
|
||||||
|
when = Math.max(when, now + MIN_UPTIME - up);
|
||||||
|
// TODO schedule for when
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RouterInfoRoutingKeyComparator implements Comparator<RouterInfo>, Serializable {
|
private static class RouterInfoRoutingKeyComparator implements Comparator<RouterInfo>, Serializable {
|
||||||
|
@ -44,7 +44,8 @@ public class PersistSybil {
|
|||||||
private static final String PFX = "sybil-";
|
private static final String PFX = "sybil-";
|
||||||
private static final String SFX = ".txt.gz";
|
private static final String SFX = ".txt.gz";
|
||||||
|
|
||||||
public PersistSybil(I2PAppContext ctx) {
|
/** access via Analysis.getPersister() */
|
||||||
|
PersistSybil(I2PAppContext ctx) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(PersistSybil.class);
|
_log = ctx.logManager().getLog(PersistSybil.class);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import net.i2p.jetty.I2PLogger;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.app.RouterApp;
|
import net.i2p.router.app.RouterApp;
|
||||||
import net.i2p.router.news.NewsManager;
|
import net.i2p.router.news.NewsManager;
|
||||||
|
import net.i2p.router.sybil.Analysis;
|
||||||
import net.i2p.router.update.ConsoleUpdateManager;
|
import net.i2p.router.update.ConsoleUpdateManager;
|
||||||
import net.i2p.util.Addresses;
|
import net.i2p.util.Addresses;
|
||||||
import net.i2p.util.FileSuffixFilter;
|
import net.i2p.util.FileSuffixFilter;
|
||||||
@ -865,6 +866,13 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
if (_mgr == null)
|
if (_mgr == null)
|
||||||
_context.addShutdownTask(new ServerShutdown());
|
_context.addShutdownTask(new ServerShutdown());
|
||||||
ConfigServiceHandler.registerSignalHandler(_context);
|
ConfigServiceHandler.registerSignalHandler(_context);
|
||||||
|
|
||||||
|
if (_mgr != null &&
|
||||||
|
_context.getBooleanProperty(HelperBase.PROP_ADVANCED) &&
|
||||||
|
_context.getProperty(Analysis.PROP_FREQUENCY, 0L) > 0) {
|
||||||
|
// registers and starts itself
|
||||||
|
Analysis.getInstance(_context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,7 +125,7 @@ public class SybilRenderer {
|
|||||||
*/
|
*/
|
||||||
private void renderRouterInfoHTML(Writer out, int mode, long date) throws IOException {
|
private void renderRouterInfoHTML(Writer out, int mode, long date) throws IOException {
|
||||||
Hash us = _context.routerHash();
|
Hash us = _context.routerHash();
|
||||||
Analysis analysis = new Analysis(_context);
|
Analysis analysis = Analysis.getInstance(_context);
|
||||||
List<RouterInfo> ris = analysis.getFloodfills(us);
|
List<RouterInfo> ris = analysis.getFloodfills(us);
|
||||||
if (ris.isEmpty()) {
|
if (ris.isEmpty()) {
|
||||||
out.write("<h3 class=\"sybils\">No known floodfills</h3>");
|
out.write("<h3 class=\"sybils\">No known floodfills</h3>");
|
||||||
@ -180,7 +180,7 @@ public class SybilRenderer {
|
|||||||
} else if (mode == 11) {
|
} else if (mode == 11) {
|
||||||
renderDestSummary(out, buf, analysis, avgMinDist, ris, points);
|
renderDestSummary(out, buf, analysis, avgMinDist, ris, points);
|
||||||
} else if (mode == 12) {
|
} else if (mode == 12) {
|
||||||
PersistSybil ps = new PersistSybil(_context);
|
PersistSybil ps = analysis.getPersister();
|
||||||
try {
|
try {
|
||||||
points = ps.load(date);
|
points = ps.load(date);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -196,7 +196,7 @@ public class SybilRenderer {
|
|||||||
long now = _context.clock().now();
|
long now = _context.clock().now();
|
||||||
points = analysis.backgroundAnalysis();
|
points = analysis.backgroundAnalysis();
|
||||||
if (!points.isEmpty()) {
|
if (!points.isEmpty()) {
|
||||||
PersistSybil ps = new PersistSybil(_context);
|
PersistSybil ps = analysis.getPersister();
|
||||||
try {
|
try {
|
||||||
ps.store(now, points);
|
ps.store(now, points);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -214,7 +214,7 @@ public class SybilRenderer {
|
|||||||
* @since 0.9.38
|
* @since 0.9.38
|
||||||
*/
|
*/
|
||||||
private void renderOverview(Writer out, StringBuilder buf, Analysis analysis) throws IOException {
|
private void renderOverview(Writer out, StringBuilder buf, Analysis analysis) throws IOException {
|
||||||
PersistSybil ps = new PersistSybil(_context);
|
PersistSybil ps = analysis.getPersister();
|
||||||
List<Long> dates = ps.load();
|
List<Long> dates = ps.load();
|
||||||
if (dates.isEmpty()) {
|
if (dates.isEmpty()) {
|
||||||
out.write("No stored analysis");
|
out.write("No stored analysis");
|
||||||
|
Reference in New Issue
Block a user