package org.redcross.openmapkit.server; import android.util.Log; import org.redcross.openmapkit.ExternalStorage; import java.io.ByteArrayInputStream; import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import fi.iki.elonen.NanoHTTPD; public class MBTilesServer extends NanoHTTPD { private static final String TAG = "MBTilesServer"; private static final int PORT = 3210; private static final Pattern TILE_PATTERN = Pattern.compile("/(.*?)/([0-9]+)/([0-9]+)/([0-9]+)\\."); private static MBTilesServer singleton; private Map<String, MBTiles> layers = new HashMap<>(); public static MBTilesServer singleton() { if (singleton == null) { singleton = new MBTilesServer(); } return singleton; } private MBTilesServer() { super(PORT); ExternalStorage.checkOrCreateAppDirs(); initializeMBTilesFiles(); } private void initializeMBTilesFiles() { File[] files = ExternalStorage.fetchMBTilesFiles(); if (files == null) return; for (File f : files) { addTiles(f.getAbsolutePath()); } } private double[] addTiles(String filePath) { double[] bounds = null; try { MBTiles mbTiles = new MBTiles(filePath); bounds = mbTiles.getBounds(); layers.put(fileNameFromPath(filePath), mbTiles); } catch(Exception ex) { Log.e(TAG, ex.toString()); } return bounds; } @Override public Response serve(IHTTPSession session) { NanoHTTPD.Response response; Method method = session.getMethod(); String uri = session.getUri(); Log.d(TAG, method + " '" + uri + "' "); Matcher matcher = TILE_PATTERN.matcher(uri); if(!matcher.find()) { response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Not found"); } else { String layerName = matcher.group(1); int z = Integer.parseInt(matcher.group(2)); int x = Integer.parseInt(matcher.group(3)); int y = Integer.parseInt(matcher.group(4)); MBTiles mbTiles = layers.get(layerName); if (mbTiles != null) { try { byte[] tile = mbTiles.getTile(z, x, y); if (tile != null) { response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "image/png", new ByteArrayInputStream(tile)); } else { response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Tile not found"); } } catch(Exception ex) { Log.e(TAG, ex.toString()); response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, ex.toString()); } } else { response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Layer not found"); } } return response; } private static String fileNameFromPath(String path) { int slashIdx = path.lastIndexOf("/"); return path.substring(slashIdx+1); } }