package org.opentripplanner.updater.traffic;
import com.beust.jcommander.internal.Maps;
import io.opentraffic.engine.data.pbf.ExchangeFormat;
import com.fasterxml.jackson.databind.JsonNode;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.traffic.Segment;
import org.opentripplanner.traffic.SegmentSpeedSample;
import org.opentripplanner.traffic.StreetSpeedSnapshot;
import org.opentripplanner.traffic.StreetSpeedSnapshotSource;
import org.opentripplanner.updater.GraphUpdaterManager;
import org.opentripplanner.updater.PollingGraphUpdater;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Map;
/**
* Update the graph with traffic data from OpenTraffic.
*/
public class OpenTrafficUpdater extends PollingGraphUpdater {
private static final Logger LOG = LoggerFactory.getLogger(OpenTrafficUpdater.class);
private Graph graph;
private GraphUpdaterManager graphUpdaterManager;
/** the tile directory to search through */
private File tileDirectory;
private boolean hasAlreadyRun = false;
@Override
protected void runPolling() throws Exception {
LOG.info("Loading speed data");
// Build a speed index now while we're running in our own thread. We'll swap it out
// at the appropriate time with a GraphWriterRunnable, but no need to synchronize yet.
Map<Segment, SegmentSpeedSample> speedIndex = Maps.newHashMap();
// search through the tile directory
for (File z : tileDirectory.listFiles()) {
for (File x : z.listFiles()) {
for (File y : x.listFiles()) {
if (!y.getName().endsWith(".traffic.pbf")) {
LOG.warn("Skipping non-traffic file {} in tile directory", y);
continue;
}
// Deserialize it
InputStream in = new BufferedInputStream(new FileInputStream(y));
ExchangeFormat.BaselineTile tile = ExchangeFormat.BaselineTile.parseFrom(in);
in.close();
// TODO: handle metadata
for (int i = 0; i < tile.getSegmentsCount(); i++) {
ExchangeFormat.BaselineStats stats = tile.getSegments(i);
SegmentSpeedSample sample;
try {
sample = new SegmentSpeedSample(stats);
} catch (IllegalArgumentException e) {
continue;
}
Segment segment = new Segment(stats.getSegment());
speedIndex.put(segment, sample);
}
}
}
}
LOG.info("Indexed {} speed samples", speedIndex.size());
graphUpdaterManager.execute(graph -> {
graph.streetSpeedSource.setSnapshot(new StreetSpeedSnapshot(speedIndex));
});
}
@Override
protected void configurePolling(Graph graph, JsonNode config) throws Exception {
this.graph = graph;
tileDirectory = new File(config.get("tileDirectory").asText());
}
@Override
public void setGraphUpdaterManager(GraphUpdaterManager updaterManager) {
updaterManager.addUpdater(this);
this.graphUpdaterManager = updaterManager;
}
@Override
public void setup() throws Exception {
graphUpdaterManager.execute(graph -> {
graph.streetSpeedSource = new StreetSpeedSnapshotSource();
});
}
@Override
public void teardown() {
graphUpdaterManager.execute(graph -> {
graph.streetSpeedSource = null;
});
}
}