diff options
| author | Keith Packard <keithp@keithp.com> | 2018-10-06 16:04:39 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2018-10-06 16:04:39 -0700 | 
| commit | 3b817a2b854065af23c9ec8e849150e6930f51e9 (patch) | |
| tree | 39e71f0f935b1fcc63654202d2d64066710095b7 | |
| parent | 5a95ed9c9419c15352b8dc1d895c9adce30f99f5 (diff) | |
map-server: Add maps proxy server
This creates a map proxy server to handle the new Google Maps API requirements
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | altoslib/AltosMapStore.java | 2 | ||||
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | map-server/Makefile.am | 1 | ||||
| -rw-r--r-- | map-server/altos-map/.gitignore | 6 | ||||
| -rw-r--r-- | map-server/altos-map/AltosMap.java | 156 | ||||
| -rw-r--r-- | map-server/altos-map/Makefile.am | 56 | ||||
| -rw-r--r-- | map-server/altos-map/Manifest.txt | 2 | ||||
| -rwxr-xr-x | map-server/altos-map/altos-map-fake | 6 | ||||
| -rw-r--r-- | map-server/altos-mapd/.gitignore | 6 | ||||
| -rw-r--r-- | map-server/altos-mapd/AltosMapd.java | 50 | ||||
| -rw-r--r-- | map-server/altos-mapd/AltosMapdClient.java | 148 | ||||
| -rw-r--r-- | map-server/altos-mapd/AltosMapdPreferences.java | 85 | ||||
| -rw-r--r-- | map-server/altos-mapd/AltosMapdServer.java | 37 | ||||
| -rw-r--r-- | map-server/altos-mapd/Makefile.am | 59 | ||||
| -rw-r--r-- | map-server/altos-mapd/Manifest.txt | 2 | 
16 files changed, 619 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index 4f47417e..89fdd6c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=ao-tools src doc icon altoslib libaltos altosuilib altosui micropeak ao-utils altosdroid telegps +SUBDIRS=ao-tools src doc icon altoslib libaltos altosuilib altosui micropeak ao-utils altosdroid telegps map-server  EXTRA_DIST = ChangeLog diff --git a/altoslib/AltosMapStore.java b/altoslib/AltosMapStore.java index 7af439c4..b1cfcbd7 100644 --- a/altoslib/AltosMapStore.java +++ b/altoslib/AltosMapStore.java @@ -68,7 +68,7 @@ public class AltosMapStore {  					     center.lat, center.lon, z, px_size/scale, px_size/scale, AltosMap.maptype_names[maptype], format_string);  	} -	public int status() { +	public synchronized int status() {  		return status;  	} diff --git a/configure.ac b/configure.ac index a14762b0..0a5a76ec 100644 --- a/configure.ac +++ b/configure.ac @@ -565,6 +565,9 @@ ao-tools/ao-usbtrng/Makefile  ao-tools/ao-chaosread/Makefile  ao-tools/ao-makebin/Makefile  ao-utils/Makefile +map-server/Makefile +map-server/altos-mapd/Makefile +map-server/altos-map/Makefile  src/Version  ]) diff --git a/map-server/Makefile.am b/map-server/Makefile.am new file mode 100644 index 00000000..f9b8a727 --- /dev/null +++ b/map-server/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=altos-mapd altos-map diff --git a/map-server/altos-map/.gitignore b/map-server/altos-map/.gitignore new file mode 100644 index 00000000..ea012eef --- /dev/null +++ b/map-server/altos-map/.gitignore @@ -0,0 +1,6 @@ +altos-map +altos-map-jdb +altos-map-test +*.jar +*.stamp +classes diff --git a/map-server/altos-map/AltosMap.java b/map-server/altos-map/AltosMap.java new file mode 100644 index 00000000..83bc7cea --- /dev/null +++ b/map-server/altos-map/AltosMap.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 altosmap; + +import java.net.*; +import java.io.*; +import java.util.*; +import java.text.*; + +import org.altusmetrum.altoslib_13.*; + +public class AltosMap { + +	public final static int port = 16717; + +	String	query_string; +	String	remote_addr; + +	public String reason_string(int code) { +		switch (code) { +		case 200: +			return "OK"; +		case 400: +			return "Bad Request"; +		case 403: +			return "Forbidden"; +		case 404: +			return "Not Found"; +		case 408: +			return "Request Timeout"; +		default: +			return "Failure"; +		} +	} + +	public void write_status(int status) { +		System.out.printf("Status: %d %s\n", status, reason_string(status)); +	} + +	public void write_type(String type) { +		System.out.printf("Content-Type: %s\n", type); +	} + +	public void fail(int status, String reason) { +		write_status(status); +		write_type("text/html"); +		System.out.printf("<body>%s</body>\n", reason); +		System.exit(1); +	} + +	public void process() { +		query_string = System.getenv("QUERY_STRING"); + +		if (query_string == null) +			fail(400, "Missing query string"); + +		remote_addr = System.getenv("REMOTE_ADDR"); + +		if (remote_addr == null) +			fail(400, "Missing remote address"); + +		String[] queries = query_string.split("&"); + +		double	lon = AltosLib.MISSING; +		double	lat = AltosLib.MISSING; +		int	zoom = AltosLib.MISSING; + +		try { +			for (String query : queries) { +				String[] q = query.split("="); +				if (q.length >= 2) { +					String name = q[0]; +					String value = q[1]; +					if (name.equals("lon")) +						lon = AltosParse.parse_double_net(value); +					else if (name.equals("lat")) +						lat = AltosParse.parse_double_net(value); +					else if (name.equals("zoom")) +						zoom = AltosParse.parse_int(value); +					else +						fail(400, String.format("Extra query param \"%s\"", query)); +				} +			} +		} catch (ParseException pe) { +			fail(400, String.format("Invalid query: %s", pe.toString())); +		} + +		if (lon == AltosLib.MISSING) +			fail(400, "Missing longitude"); +		if (lat == AltosLib.MISSING) +			fail(400, "Missing latitude"); +		if (zoom == AltosLib.MISSING) +			fail(400, "Missing zoom"); + +		try { +			Socket	socket = new Socket(InetAddress.getLoopbackAddress(), port); + +			AltosJson	request = new AltosJson(); + +			request.put("lat", lat); +			request.put("lon", lon); +			request.put("zoom", zoom); +			request.put("remote_addr", remote_addr); + +			Writer writer = new PrintWriter(socket.getOutputStream()); +			request.write(writer); +			writer.flush(); + +			AltosJson	reply = AltosJson.fromInputStream(socket.getInputStream()); + +			int status = reply.get_int("status", 400); + +			if (status != 200) +				fail(status, "Bad cache status"); + +			String filename = reply.get_string("filename", null); +			try { +				File file = new File(filename); +				long length = file.length(); +				FileInputStream in = new FileInputStream(file); +				String content_type = reply.get_string("content_type", null); +				System.out.printf("Content-Type: %s\n", content_type); +				System.out.printf("Content-Length: %d\n", file.length()); +				byte[] buf = new byte[4096]; +				int bytes_read; +				while ((bytes_read = in.read(buf)) > 0) +					System.out.write(buf); +			} catch (IOException ie) { +				fail(404, String.format("IO Exception: %s", ie.toString())); +			} +		} catch (Exception e) { +			fail(404, String.format("Exception %s", e.toString())); +		} +	} + +	public AltosMap() { +	} + +	public static void main(final String[] args) { + +		new AltosMap().process(); + +	} +} diff --git a/map-server/altos-map/Makefile.am b/map-server/altos-map/Makefile.am new file mode 100644 index 00000000..efaae457 --- /dev/null +++ b/map-server/altos-map/Makefile.am @@ -0,0 +1,56 @@ +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-map + +altosmap_JAVA = \ +	AltosMap.java + +ALTOSLIB_CLASS=\ +	altoslib_$(ALTOSLIB_VERSION).jar + +JAR=altosmap.jar + +FATJAR=altosmap-fat.jar + +all-local: classes/altosmap $(JAR) altos-map altos-map-test altos-map-jdb + +classes/altosmap: +	mkdir -p classes/altosmap + +$(JAR): classaltosmap.stamp Manifest.txt $(ALTOSLIB_CLASS) +	jar cfm $@ Manifest.txt \ +		-C classes altosmap + +altosmapdir=$(datadir)/java + +$(FATJAR): classaltosmap.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) +	jar cfm $@ Manifest-fat.txt \ +		-C classes altosmap + +altos-map: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(altosmapdir)/altosmap.jar" "$$@"' >> $@ +	chmod +x $@ + +altos-map-test: Makefile +	echo '#!/bin/sh' > $@ +	echo 'dir="$$(dirname $$0)"' >> $@ +	echo 'cd "$$dir"' >> $@ +	echo 'altosmap="$$(pwd -P)"' >> $@ +	echo 'exec java -jar "$$altosmap/altosmap.jar" "$$@"' >> $@ +	chmod +x $@ + +altos-map-jdb: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec jdb altosmap/AltosMap "$$@"' >> $@ +	chmod +x $@ + +$(ALTOSLIB_CLASS): +	-rm -f "$@" +	$(LN_S) ../../altoslib/"$@" . + diff --git a/map-server/altos-map/Manifest.txt b/map-server/altos-map/Manifest.txt new file mode 100644 index 00000000..1a285b40 --- /dev/null +++ b/map-server/altos-map/Manifest.txt @@ -0,0 +1,2 @@ +Main-Class: altosmap.AltosMap +Class-Path: altoslib_13.jar diff --git a/map-server/altos-map/altos-map-fake b/map-server/altos-map/altos-map-fake new file mode 100755 index 00000000..a78bbd64 --- /dev/null +++ b/map-server/altos-map/altos-map-fake @@ -0,0 +1,6 @@ +#!/bin/sh +# map-N43.799102,W120.586281-hybrid-20.jpg +export QUERY_STRING="lat=43.799102&lon=-120.586281&zoom=20" +export REMOTE_ADDR="127.0.0.1" +./altos-map-test + 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..cfa1ef35 --- /dev/null +++ b/map-server/altos-mapd/AltosMapd.java @@ -0,0 +1,50 @@ +/* + * 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 org.altusmetrum.altoslib_13.*; + +public class AltosMapd { + +	public final 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 void main(final String[] args) { + +		AltosMapdServer server = new AltosMapdServer(port); + +		AltosPreferences.init(new AltosMapdPreferences()); + +		AltosPreferences.mapdir = new File("/home/keithp/misc/rockets/flights/maps"); + +		for (;;) { +			Socket client = server.accept(); +			if (client == null) { +				System.out.printf("accept failed\n"); +				continue; +			} +			System.out.printf("got client\n"); +			new AltosMapdClient(client); +		} +	} +} diff --git a/map-server/altos-mapd/AltosMapdClient.java b/map-server/altos-mapd/AltosMapdClient.java new file mode 100644 index 00000000..fb0c08e6 --- /dev/null +++ b/map-server/altos-mapd/AltosMapdClient.java @@ -0,0 +1,148 @@ +/* + * 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 void set_status(int 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()); + +			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 { +				store_ready = new Semaphore(0); + +				System.out.printf("Fetching tile for %g %g %d\n", lat, lon, zoom); + +				AltosMapStore	map_store = AltosMapStore.get(new AltosLatLon(lat, lon), +									      zoom, +									      AltosMapd.maptype, +									      AltosMapd.px_size, +									      AltosMapd.scale); +				int status; + +				if (map_store == null) { +					System.out.printf("no store?\n"); +					status = AltosMapTile.failed; +				} else { +					map_store.add_listener(this); + +					System.out.printf("Waiting for tile\n"); + +					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); +				} +			} +		} 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) { +			} +			System.out.printf("client done\n"); +		} +	} + +	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..68b427f0 --- /dev/null +++ b/map-server/altos-mapd/AltosMapdServer.java @@ -0,0 +1,37 @@ +/* + * 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.*; + +public class AltosMapdServer { +	ServerSocket	socket; + +	public Socket accept() { +		try { +			return socket.accept(); +		} catch (Exception e) { +			return null; +		} +	} + +	public AltosMapdServer(int port) { +		try { +			socket = new ServerSocket(port, 5, InetAddress.getLoopbackAddress()); +		} catch (Exception e) { +			socket = null; +		} +	} +} diff --git a/map-server/altos-mapd/Makefile.am b/map-server/altos-mapd/Makefile.am new file mode 100644 index 00000000..c099d1c7 --- /dev/null +++ b/map-server/altos-mapd/Makefile.am @@ -0,0 +1,59 @@ +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 + +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  | 
