package com.subgraph.orchid.circuits;
import com.subgraph.orchid.crypto.TorRandom;
public class CircuitStatus {
enum CircuitState {
UNCONNECTED("Unconnected"),
BUILDING("Building"),
FAILED("Failed"),
OPEN("Open"),
DESTROYED("Destroyed");
String name;
CircuitState(String name) { this.name = name; }
public String toString() { return name; }
}
private long timestampCreated;
private long timestampDirty;
private int currentStreamId;
private Object streamIdLock = new Object();
private volatile CircuitState state = CircuitState.UNCONNECTED;
CircuitStatus() {
initializeCurrentStreamId();
}
private void initializeCurrentStreamId() {
final TorRandom random = new TorRandom();
currentStreamId = random.nextInt(0xFFFF) + 1;
}
synchronized void updateCreatedTimestamp() {
timestampCreated = System.currentTimeMillis();
timestampDirty = 0;
}
synchronized void updateDirtyTimestamp() {
if(timestampDirty == 0 && state != CircuitState.BUILDING) {
timestampDirty = System.currentTimeMillis();
}
}
synchronized long getMillisecondsElapsedSinceCreated() {
return millisecondsElapsedSince(timestampCreated);
}
synchronized long getMillisecondsDirty() {
return millisecondsElapsedSince(timestampDirty);
}
private static long millisecondsElapsedSince(long then) {
if(then == 0) {
return 0;
}
final long now = System.currentTimeMillis();
return now - then;
}
synchronized boolean isDirty() {
return timestampDirty != 0;
}
void setStateBuilding() {
state = CircuitState.BUILDING;
}
void setStateFailed() {
state = CircuitState.FAILED;
}
void setStateOpen() {
state = CircuitState.OPEN;
}
void setStateDestroyed() {
state = CircuitState.DESTROYED;
}
boolean isBuilding() {
return state == CircuitState.BUILDING;
}
boolean isConnected() {
return state == CircuitState.OPEN;
}
boolean isUnconnected() {
return state == CircuitState.UNCONNECTED;
}
String getStateAsString() {
if(state == CircuitState.OPEN) {
return state.toString() + " ["+ getDirtyString() + "]";
}
return state.toString();
}
private String getDirtyString() {
if(!isDirty()) {
return "Clean";
} else {
return "Dirty "+ (getMillisecondsDirty() / 1000) +"s";
}
}
int nextStreamId() {
synchronized(streamIdLock) {
currentStreamId++;
if(currentStreamId > 0xFFFF)
currentStreamId = 1;
return currentStreamId;
}
}
}