Skip to content

Commit

Permalink
Merge pull request #932 from conveyal/multi-grid-download
Browse files Browse the repository at this point in the history
Make human-friendly names available and allow multi-grid downloads
  • Loading branch information
abyrd authored Mar 28, 2024
2 parents e42274e + b4933c6 commit 953757c
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.conveyal.analysis.persistence.AnalysisDB;
import com.conveyal.analysis.util.JsonUtil;
import com.conveyal.file.FileStorage;
import com.conveyal.file.UrlWithHumanName;
import com.conveyal.r5.analyst.progress.Task;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.bson.conversions.Bson;
Expand All @@ -27,6 +28,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;
import static org.eclipse.jetty.http.MimeTypes.Type.APPLICATION_JSON;

/**
* Stores vector aggregationAreas (used to define the region of a weighted average accessibility metric).
Expand Down Expand Up @@ -98,10 +100,10 @@ private Collection<AggregationArea> getAggregationAreas (Request req, Response r
}

/** Returns a JSON-wrapped URL for the mask grid of the aggregation area whose id matches the path parameter. */
private ObjectNode getAggregationAreaGridUrl (Request req, Response res) {
private UrlWithHumanName getAggregationAreaGridUrl (Request req, Response res) {
AggregationArea aggregationArea = aggregationAreaCollection.findPermittedByRequestParamId(req);
String url = fileStorage.getURL(aggregationArea.getStorageKey());
return JsonUtil.objectNode().put("url", url);
res.type(APPLICATION_JSON.asString());
return fileStorage.getJsonUrl(aggregationArea.getStorageKey(), aggregationArea.name, "grid");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ private Object getFile (Request req, Response res) throws Exception {
FileStorageKey key = new FileStorageKey(category, filename);
File file = fileStorage.getFile(key);
FileStorageFormat format = FileStorageFormat.fromFilename(filename);
res.type(format.mimeType);
if (format != null) {
res.type(format.mimeType);
}

// If the content-encoding is set to gzip, Spark automatically gzips the response. This double-gzips anything
// that was already gzipped. Some of our files are already gzipped, and we rely on the the client browser to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.conveyal.file.FileStorageFormat;
import com.conveyal.file.FileStorageKey;
import com.conveyal.file.FileUtils;
import com.conveyal.file.UrlWithHumanName;
import com.conveyal.r5.analyst.FreeFormPointSet;
import com.conveyal.r5.analyst.Grid;
import com.conveyal.r5.analyst.PointSet;
Expand Down Expand Up @@ -61,6 +62,7 @@
import static com.conveyal.file.FileCategory.GRIDS;
import static com.conveyal.r5.analyst.WebMercatorExtents.parseZoom;
import static com.conveyal.r5.analyst.progress.WorkProductType.OPPORTUNITY_DATASET;
import static org.eclipse.jetty.http.MimeTypes.Type.APPLICATION_JSON;

/**
* Controller that handles fetching opportunity datasets (grids and other pointset formats).
Expand Down Expand Up @@ -94,10 +96,6 @@ public OpportunityDatasetController (
/** Store upload status objects FIXME trivial Javadoc */
private final List<OpportunityDatasetUploadStatus> uploadStatuses = new ArrayList<>();

private ObjectNode getJsonUrl (FileStorageKey key) {
return JsonUtil.objectNode().put("url", fileStorage.getURL(key));
}

private void addStatusAndRemoveOldStatuses(OpportunityDatasetUploadStatus status) {
uploadStatuses.add(status);
LocalDateTime now = LocalDateTime.now();
Expand All @@ -113,10 +111,11 @@ private Collection<OpportunityDataset> getRegionDatasets(Request req, Response r
);
}

private Object getOpportunityDataset(Request req, Response res) {
private UrlWithHumanName getOpportunityDataset(Request req, Response res) {
OpportunityDataset dataset = Persistence.opportunityDatasets.findByIdFromRequestIfPermitted(req);
if (dataset.format == FileStorageFormat.GRID) {
return getJsonUrl(dataset.getStorageKey());
res.type(APPLICATION_JSON.asString());
return fileStorage.getJsonUrl(dataset.getStorageKey(), dataset.sourceName + "_" + dataset.name, "grid");
} else {
// Currently the UI can only visualize grids, not other kinds of datasets (freeform points).
// We do generate a rasterized grid for each of the freeform pointsets we create, so ideally we'd redirect
Expand Down Expand Up @@ -564,9 +563,10 @@ private List<Grid> createGridsFromShapefile(List<FileItem> fileItems,
* Respond to a request with a redirect to a downloadable file.
* @param req should specify regionId, opportunityDatasetId, and an available download format (.tiff or .grid)
*/
private Object downloadOpportunityDataset (Request req, Response res) throws IOException {
private UrlWithHumanName downloadOpportunityDataset (Request req, Response res) throws IOException {
FileStorageFormat downloadFormat;
String format = req.params("format");
res.type(APPLICATION_JSON.asString());
try {
downloadFormat = FileStorageFormat.valueOf(format.toUpperCase());
} catch (IllegalArgumentException iae) {
Expand All @@ -576,38 +576,32 @@ private Object downloadOpportunityDataset (Request req, Response res) throws IOE
String regionId = req.params("_id");
String gridKey = format;
FileStorageKey storageKey = new FileStorageKey(GRIDS, String.format("%s/%s.grid", regionId, gridKey));
return getJsonUrl(storageKey);
return fileStorage.getJsonUrl(storageKey, gridKey, "grid");
}
if (FileStorageFormat.GRID.equals(downloadFormat)) {
return getOpportunityDataset(req, res);
}

if (FileStorageFormat.GRID.equals(downloadFormat)) return getOpportunityDataset(req, res);

final OpportunityDataset opportunityDataset = Persistence.opportunityDatasets.findByIdFromRequestIfPermitted(req);

FileStorageKey gridKey = opportunityDataset.getStorageKey(FileStorageFormat.GRID);
FileStorageKey formatKey = opportunityDataset.getStorageKey(downloadFormat);

// if this grid is not on S3 in the requested format, try to get the .grid format
if (!fileStorage.exists(gridKey)) {
throw AnalysisServerException.notFound("Requested grid does not exist.");
}

if (!fileStorage.exists(formatKey)) {
// get the grid and convert it to the requested format
File gridFile = fileStorage.getFile(gridKey);
Grid grid = Grid.read(new GZIPInputStream(new FileInputStream(gridFile))); // closes input stream
File localFile = FileUtils.createScratchFile(downloadFormat.toString());
FileOutputStream fos = new FileOutputStream(localFile);

if (FileStorageFormat.PNG.equals(downloadFormat)) {
grid.writePng(fos);
} else if (FileStorageFormat.GEOTIFF.equals(downloadFormat)) {
grid.writeGeotiff(fos);
}

fileStorage.moveIntoStorage(formatKey, localFile);
}

return getJsonUrl(formatKey);
return fileStorage.getJsonUrl(formatKey, opportunityDataset.sourceName + "_" + opportunityDataset.name, downloadFormat.extension);
}

/**
Expand Down
Loading

0 comments on commit 953757c

Please sign in to comment.