diff options
Diffstat (limited to 'map-server/altos-mapd')
-rw-r--r-- | map-server/altos-mapd/.gitignore | 6 | ||||
-rw-r--r-- | map-server/altos-mapd/AltosMapd.java | 235 | ||||
-rw-r--r-- | map-server/altos-mapd/AltosMapdClient.java | 156 | ||||
-rw-r--r-- | map-server/altos-mapd/AltosMapdPreferences.java | 85 | ||||
-rw-r--r-- | map-server/altos-mapd/AltosMapdServer.java | 24 | ||||
-rw-r--r-- | map-server/altos-mapd/Makefile.am | 73 | ||||
-rw-r--r-- | map-server/altos-mapd/Manifest.txt | 2 | ||||
-rw-r--r-- | map-server/altos-mapd/altos-mapd-default | 4 | ||||
-rw-r--r-- | map-server/altos-mapd/altos-mapd.service | 14 |
9 files changed, 599 insertions, 0 deletions
diff --git a/map-server/altos-mapd/.gitignore b/map-server/altos-mapd/.gitignore new file mode 100644 index 00000000..5f5ce0ae --- /dev/null +++ b/map-server/altos-mapd/.gitignore @@ -0,0 +1,6 @@ +*.stamp +*.jar +altos-mapd +altos-mapd-jdb +altos-mapd-test +classes diff --git a/map-server/altos-mapd/AltosMapd.java b/map-server/altos-mapd/AltosMapd.java new file mode 100644 index 00000000..29528541 --- /dev/null +++ b/map-server/altos-mapd/AltosMapd.java @@ -0,0 +1,235 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +package altosmapd; + +import java.net.*; +import java.io.*; +import java.text.*; +import java.util.*; +import java.util.concurrent.*; + +import org.altusmetrum.altoslib_13.*; + +public class AltosMapd implements AltosLaunchSiteListener { + + public static int port = 16717; + + public final static int maptype = AltosMap.maptype_hybrid; + + public final static int px_size = 512; + + public final static int scale = 1; + + public static int max_zoom = 17; + + public static double valid_radius = 17000; /* 17km */ + + public String map_dir = null; + public String launch_sites_file = null; + public String key_file = null; + + public void usage() { + System.out.printf("usage: altos-mapd [--mapdir <map-directory] [--launch-sites <launch-sites-file>]\n" + + " [--radius <valid-radius-m> [--port <port>] [--key <key-file>]\n" + + " [--max-zoom <max-zoom-level>\n"); + System.exit(1); + } + + private static Semaphore launch_sites_ready; + + private static List<AltosLaunchSite> launch_sites; + + public void notify_launch_sites(List<AltosLaunchSite> sites) { + synchronized (launch_sites_ready) { + if (sites != null) { + launch_sites = sites; + launch_sites_ready.release(); + } + } + } + + private static boolean west_of(double a, double b) { + double diff = b - a; + + while (diff >= 360.0) + diff -= 360.0; + while (diff <= -360.0) + diff += 360.0; + + return diff >= 0; + } + + public static boolean check_lat_lon(double lat, double lon, int zoom) { + + if (zoom > max_zoom) + return false; + + AltosMapTransform transform = new AltosMapTransform(px_size, px_size, zoom, new AltosLatLon(lat, lon)); + + AltosLatLon upper_left = transform.screen_lat_lon(new AltosPointInt(0, 0)); + AltosLatLon lower_right = transform.screen_lat_lon(new AltosPointInt(px_size, px_size)); + + synchronized (launch_sites_ready) { + if (launch_sites == null) { + try { + launch_sites_ready.acquire(); + } catch (InterruptedException ie) { + return false; + } + } + } + if (launch_sites == null) { + System.out.printf("No launch site data available, refusing all requests\n"); + return false; + } + + for (AltosLaunchSite site : launch_sites) { + + /* Figure out which point in the tile to + * measure to the site That's one of the edges + * or the site location depend on where the + * site is in relation to the tile + */ + + double check_lon; + + if (west_of(site.longitude, upper_left.lon)) + check_lon = upper_left.lon; + else if (west_of(lower_right.lon, site.longitude)) + check_lon = lower_right.lon; + else + check_lon = site.longitude; + + double check_lat; + + if (site.latitude < lower_right.lat) + check_lat = lower_right.lat; + else if (upper_left.lat < site.latitude) + check_lat = upper_left.lat; + else + check_lat = site.latitude; + + AltosGreatCircle gc = new AltosGreatCircle(site.latitude, site.longitude, + check_lat, check_lon); + + if (gc.distance <= valid_radius) + return true; + } + + return false; + } + + AltosMapdServer server; + + public void process(String[] args) { + + AltosPreferences.init(new AltosMapdPreferences()); + + int skip = 1; + for (int i = 0; i < args.length; i += skip) { + skip = 1; + if (args[i].equals("--mapdir") && i < args.length-1) { + map_dir = args[i+1]; + skip = 2; + } else if (args[i].equals("--launch-sites") && i < args.length-1) { + launch_sites_file = args[i+1]; + skip = 2; + } else if (args[i].equals("--radius") && i < args.length-1) { + try { + valid_radius = AltosParse.parse_double_locale(args[i+1]); + } catch (ParseException pe) { + usage(); + } + skip = 2; + } else if (args[i].equals("--port") && i < args.length-1) { + try { + port = AltosParse.parse_int(args[i+1]); + } catch (ParseException pe) { + usage(); + } + skip = 2; + } else if (args[i].equals("--key") && i < args.length-1) { + key_file = args[i+1]; + skip = 2; + } else if (args[i].equals("--max-zoom") && i < args.length-1) { + try { + max_zoom = AltosParse.parse_int(args[i+1]); + } catch (ParseException pe) { + usage(); + } + skip = 2; + } else { + usage(); + } + } + + if (map_dir == null) + usage(); + + if (key_file != null) { + try { + BufferedReader key_reader = new BufferedReader(new FileReader(key_file)); + + String line = key_reader.readLine(); + if (line == null || line.length() != 39) { + System.out.printf("%s: invalid contents %d \"%s\"\n", + key_file, line.length(), line); + usage(); + } + key_reader.close(); + AltosMapStore.google_maps_api_key = line; + } catch (Exception e) { + System.out.printf("%s: %s\n", key_file, e.toString()); + usage(); + } + } + + AltosPreferences.mapdir = new File(map_dir); + + if (launch_sites_file != null) + AltosLaunchSites.launch_sites_url = "file://" + launch_sites_file; + + launch_sites_ready = new Semaphore(0); + + new AltosLaunchSites(this); + + try { + server = new AltosMapdServer(port); + } catch (IOException ie) { + System.out.printf("Cannot bind to port %d: %s\n", port, ie.toString()); + usage(); + } + + for (;;) { + try { + Socket client = server.accept(); + if (client == null) { + System.out.printf("accept failed\n"); + continue; + } + new AltosMapdClient(client); + } catch (Exception e) { + System.out.printf("Exception %s\n", e.toString()); + } + } + } + + public void AltosMapd() { + } + + public static void main(final String[] args) { + new AltosMapd().process(args); + } +} diff --git a/map-server/altos-mapd/AltosMapdClient.java b/map-server/altos-mapd/AltosMapdClient.java new file mode 100644 index 00000000..6c95da8f --- /dev/null +++ b/map-server/altos-mapd/AltosMapdClient.java @@ -0,0 +1,156 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +package altosmapd; + +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.*; + +import org.altusmetrum.altoslib_13.*; + +public class AltosMapdClient extends Thread implements AltosMapStoreListener { + private Socket socket; + private AltosJson request; + private AltosJson reply; + + private int http_status; + + private void set_status(int status) { + http_status = status; + reply.put("status", status); + } + + private void set_filename(String filename) { + reply.put("filename", filename); + + } + + private void set_content_type(String content_type) { + reply.put("content_type", content_type); + } + + private String content_type(File file) { + String content_type = "application/octet-stream"; + String basename = file.getName(); + if (basename.endsWith(".jpg")) + content_type = "image/jpeg"; + if (basename.endsWith(".png")) + content_type = "image/png"; + return content_type; + } + + private void set_file(File file) { + set_filename(file.getAbsolutePath()); + set_content_type(content_type(file)); + } + + private Semaphore store_ready; + + public void notify_store(AltosMapStore map_store, int status) { + if (status != AltosMapTile.fetching) + store_ready.release(); + } + + public void run() { + reply = new AltosJson(); + try { + request = AltosJson.fromInputStream(socket.getInputStream()); + + if (request == null) { + set_status(400); + System.out.printf("client failed %d\n", http_status); + } else { + + double lat = request.get_double("lat", AltosLib.MISSING); + double lon = request.get_double("lon", AltosLib.MISSING); + int zoom = request.get_int("zoom", AltosLib.MISSING); + String addr = request.get_string("remote_addr", null); + + if (lat == AltosLib.MISSING || + lon == AltosLib.MISSING || + zoom == AltosLib.MISSING || + addr == null) + { + set_status(400); + } else if (!AltosMapd.check_lat_lon(lat, lon, zoom)) { + set_status(403); /* Forbidden */ + } else { + + store_ready = new Semaphore(0); + + AltosMapStore map_store = AltosMapStore.get(new AltosLatLon(lat, lon), + zoom, + AltosMapd.maptype, + AltosMapd.px_size, + AltosMapd.scale); + int status; + + if (map_store == null) { + status = AltosMapTile.failed; + } else { + map_store.add_listener(this); + + try { + store_ready.acquire(); + } catch (Exception ie) { + } + + status = map_store.status(); + } + + if (status == AltosMapTile.fetched || status == AltosMapTile.loaded) { + set_status(200); + set_file(map_store.file); + } else if (status == AltosMapTile.failed) { + set_status(404); + } else if (status == AltosMapTile.fetching) { + set_status(408); + } else if (status == AltosMapTile.bad_request) { + set_status(400); + } else if (status == AltosMapTile.forbidden) { + set_status(403); + } else { + set_status(400); + } + } + System.out.printf("%s: %.6f %.6f %d status %d\n", + addr, lat, lon, zoom, http_status); + } + } catch (Exception e) { + System.out.printf("client exception %s\n", e.toString()); + e.printStackTrace(System.out); + set_status(400); + + } finally { + try { + Writer writer = new PrintWriter(socket.getOutputStream()); + reply.write(writer); + writer.write('\n'); + writer.flush(); + } catch (IOException ie) { + } + try { + socket.close(); + } catch (IOException ie) { + } + } + } + + public AltosMapdClient(Socket socket) { + this.socket = socket; + start(); + } +} diff --git a/map-server/altos-mapd/AltosMapdPreferences.java b/map-server/altos-mapd/AltosMapdPreferences.java new file mode 100644 index 00000000..fcfe3261 --- /dev/null +++ b/map-server/altos-mapd/AltosMapdPreferences.java @@ -0,0 +1,85 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +package altosmapd; + +import java.io.*; + +import org.altusmetrum.altoslib_13.*; + +public class AltosMapdPreferences extends AltosPreferencesBackend { + + public String getString(String key, String def) { + return def; + } + public void putString(String key, String value) { + } + + public int getInt(String key, int def) { + return def; + } + + public void putInt(String key, int value) { + } + + public double getDouble(String key, double def) { + return def; + } + + public void putDouble(String key, double value) { + } + + public boolean getBoolean(String key, boolean def) { + return def; + } + + public void putBoolean(String key, boolean value) { + } + + public byte[] getBytes(String key, byte[] def) { + return def; + } + + public void putBytes(String key, byte[] value) { + } + + public boolean nodeExists(String key) { + return false; + } + + public AltosPreferencesBackend node(String key) { + return this; + } + + public String[] keys() { + return null; + } + + public void remove(String key) { + } + + public void flush() { + } + + public File homeDirectory() { + return new File ("."); + } + + public void debug(String format, Object ... arguments) { + System.out.printf(format, arguments); + } + + public AltosMapdPreferences() { + } +} diff --git a/map-server/altos-mapd/AltosMapdServer.java b/map-server/altos-mapd/AltosMapdServer.java new file mode 100644 index 00000000..db7f7dc1 --- /dev/null +++ b/map-server/altos-mapd/AltosMapdServer.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2018 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +package altosmapd; + +import java.net.*; +import java.io.*; + +public class AltosMapdServer extends ServerSocket { + public AltosMapdServer(int port) throws IOException { + super(port, 256, InetAddress.getLoopbackAddress()); + } +} diff --git a/map-server/altos-mapd/Makefile.am b/map-server/altos-mapd/Makefile.am new file mode 100644 index 00000000..39f67536 --- /dev/null +++ b/map-server/altos-mapd/Makefile.am @@ -0,0 +1,73 @@ +JAVAROOT=classes +AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6 + +altoslibdir=$(libdir)/altos + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="$(JAVAROOT):../../altoslib/*" + +bin_SCRIPTS=altos-mapd + +altosmapd_JAVA = \ + AltosMapd.java \ + AltosMapdServer.java \ + AltosMapdClient.java \ + AltosMapdPreferences.java + +ALTOSLIB_CLASS=\ + altoslib_$(ALTOSLIB_VERSION).jar + +JAR=altosmapd.jar + +FATJAR=altosmapd-fat.jar + +all-local: classes/altosmapd $(JAR) altos-mapd altos-mapd-test altos-mapd-jdb + +defaultsdir=$(sysconfdir)/default + +defaults_DATA=altos-mapd-default + +systemddir=$(libdir)/systemd/system + +systemd_DATA=altos-mapd.service + +install-altosmapdJAVA: altosmapd.jar + @$(NORMAL_INSTALL) + test -z "$(altosmapddir)" || $(MKDIR_P) "$(DESTDIR)$(altosmapddir)" + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosmapddir)/altosdmap.jar'"; \ + $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosmapddir)" + +classes/altosmapd: + mkdir -p classes/altosmapd + +$(JAR): classaltosmapd.stamp Manifest.txt $(ALTOSLIB_CLASS) + jar cfm $@ Manifest.txt \ + -C classes altosmapd + +altosmapddir=$(datadir)/java + +$(FATJAR): classaltosmapd.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) + jar cfm $@ Manifest-fat.txt \ + -C classes altosmapd + +altos-mapd: Makefile + echo "#!/bin/sh" > $@ + echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(altosmapddir)/altosmapd.jar" "$$@"' >> $@ + chmod +x $@ + +altos-mapd-test: Makefile + echo '#!/bin/sh' > $@ + echo 'dir="$$(dirname $$0)"' >> $@ + echo 'cd "$$dir"' >> $@ + echo 'altosmapd="$$(pwd -P)"' >> $@ + echo 'exec java -jar "$$altosmapd/altosmapd.jar" "$$@"' >> $@ + chmod +x $@ + +altos-mapd-jdb: Makefile + echo "#!/bin/sh" > $@ + echo 'exec jdb altosmapd/AltosMapd "$$@"' >> $@ + chmod +x $@ + +$(ALTOSLIB_CLASS): + -rm -f "$@" + $(LN_S) ../../altoslib/"$@" . + diff --git a/map-server/altos-mapd/Manifest.txt b/map-server/altos-mapd/Manifest.txt new file mode 100644 index 00000000..42c0313b --- /dev/null +++ b/map-server/altos-mapd/Manifest.txt @@ -0,0 +1,2 @@ +Main-Class: altosmapd.AltosMapd +Class-Path: altoslib_13.jar diff --git a/map-server/altos-mapd/altos-mapd-default b/map-server/altos-mapd/altos-mapd-default new file mode 100644 index 00000000..1611f0b6 --- /dev/null +++ b/map-server/altos-mapd/altos-mapd-default @@ -0,0 +1,4 @@ +MAPKEY=/home/altos-mapd/google-maps-api-key +MAPDIR=/home/altos-mapd/maps +LAUNCHSITES=/var/www/html/launch-sites.txt +MAXZOOM=17 diff --git a/map-server/altos-mapd/altos-mapd.service b/map-server/altos-mapd/altos-mapd.service new file mode 100644 index 00000000..ba263c2a --- /dev/null +++ b/map-server/altos-mapd/altos-mapd.service @@ -0,0 +1,14 @@ +[Unit] +Description=AltOS Map Cache +Requires=network-online.target +After=network-online.target + +[Service] +Type=simple +User=altos-mapd +Restart=always +EnvironmentFile=/etc/default/altos-mapd-default +ExecStart=/usr/bin/altos-mapd --key $MAPKEY --mapdir $MAPDIR --launch-sites $LAUNCHSITES --max-zoom $MAXZOOM + +[Install] +WantedBy=multi-user.target |