package com.subgraph.orchid.circuits;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.subgraph.orchid.dashboard.DashboardRenderable;
import com.subgraph.orchid.dashboard.DashboardRenderer;
public class CircuitPredictor implements DashboardRenderable {
private final static Integer INTERNAL_CIRCUIT_PORT_VALUE = 0;
private final static long TIMEOUT_MS = 60 * 60 * 1000; // One hour
private final Map<Integer, Long> portsSeen;
public CircuitPredictor() {
portsSeen = new HashMap<Integer,Long>();
addExitPortRequest(80);
addInternalRequest();
}
void addExitPortRequest(int port) {
synchronized (portsSeen) {
portsSeen.put(port, System.currentTimeMillis());
}
}
void addInternalRequest() {
addExitPortRequest(INTERNAL_CIRCUIT_PORT_VALUE);
}
private boolean isEntryExpired(Entry<Integer, Long> e, long now) {
return (now - e.getValue()) > TIMEOUT_MS;
}
private void removeExpiredPorts() {
final long now = System.currentTimeMillis();
final Iterator<Entry<Integer, Long>> it = portsSeen.entrySet().iterator();
while(it.hasNext()) {
if(isEntryExpired(it.next(), now)) {
it.remove();
}
}
}
boolean isInternalPredicted() {
synchronized (portsSeen) {
removeExpiredPorts();
return portsSeen.containsKey(INTERNAL_CIRCUIT_PORT_VALUE);
}
}
Set<Integer> getPredictedPorts() {
synchronized (portsSeen) {
removeExpiredPorts();
final Set<Integer> result = new HashSet<Integer>(portsSeen.keySet());
result.remove(INTERNAL_CIRCUIT_PORT_VALUE);
return result;
}
}
List<PredictedPortTarget> getPredictedPortTargets() {
final List<PredictedPortTarget> targets = new ArrayList<PredictedPortTarget>();
for(int p: getPredictedPorts()) {
targets.add(new PredictedPortTarget(p));
}
return targets;
}
public void dashboardRender(DashboardRenderer renderer, PrintWriter writer, int flags)
throws IOException {
if((flags & DASHBOARD_PREDICTED_PORTS) == 0) {
return;
}
writer.println("[Predicted Ports] ");
for(int port : portsSeen.keySet()) {
writer.write(" "+ port);
Long lastSeen = portsSeen.get(port);
if(lastSeen != null) {
long now = System.currentTimeMillis();
long ms = now - lastSeen;
writer.write(" (last seen "+ TimeUnit.MINUTES.convert(ms, TimeUnit.MILLISECONDS) +" minutes ago)");
}
writer.println();
}
writer.println();
}
}