b390275a9ff6f850240ade60d9c0e0faf8370046
[web/altusmetrum] / AltOS / doc / map-loading.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta name="generator" content="Asciidoctor 2.0.10">
8 <meta name="author" content="Keith Packard">
9 <meta name="copyright" content="Keith Packard 2018">
10 <title>Loading Map Tiles from Google Maps</title>
11 <link rel="stylesheet" href="./am-notoc.css">
12 </head>
13 <body class="article">
14 <div id="header">
15 <h1>Loading Map Tiles from Google Maps</h1>
16 <div class="details">
17 <span id="author" class="author">Keith Packard</span><br>
18 <span id="email" class="email"><a href="mailto:keithp@keithp.com">keithp@keithp.com</a></span><br>
19 </div>
20 </div>
21 <div id="content">
22 <div class="sect1">
23 <h2 id="_the_google_maps_problem">The Google Maps Problem</h2>
24 <div class="sectionbody">
25 <div class="paragraph">
26 <p>Until recently, Google Maps could be used without fee to fetch map
27 tiles. Applications could load map tiles anonymously or using a key;
28 when used anonymously, the number of tiles that could be loaded per
29 day and the rate at which tiles could be loaded was throttled to make
30 the API practical only for development purpose. With an application
31 key, the number of tiles available per day was much higher, and there
32 was no rate limiting. This was usually sufficient for Altos Metrum
33 customer use.</p>
34 </div>
35 <div class="paragraph">
36 <p>However, this has changed and now there is no way to load map tiles
37 anonymously, and any application key must be tied to a credit
38 card. The tile cap for free usage is now monthly instead of
39 daily. Because the key is tied to a credit card, we should not ship it
40 with the application any longer. And because the cap is monthly
41 instead of daily, we need some way to control usage by our
42 applications.</p>
43 </div>
44 <div class="sect2">
45 <h3 id="_the_proposed_solution_an_intermediate_service">The Proposed Solution — An Intermediate Service</h3>
46 <div class="paragraph">
47 <p>To give us some measure of control over tile loading, we will want to
48 interpose a server controlled by us between the application and Google
49 Maps. This will let us store the Google Maps key in a secure location,
50 and also control tile loading by each user.</p>
51 </div>
52 <div class="imageblock text-center">
53 <div class="content">
54 <img src="map-loading.svg" alt="map loading">
55 </div>
56 </div>
57 </div>
58 </div>
59 </div>
60 <div class="sect1">
61 <h2 id="_altos_map_service">AltOS Map Service</h2>
62 <div class="sectionbody">
63 <div class="paragraph">
64 <p>This service receives a URL request and replies with either a map tile
65 or an error. It is functionally equivalent to the Google Maps service,
66 except that it can control use of the Google Maps API.</p>
67 </div>
68 <div class="sect2">
69 <h3 id="_altos_map_cgi_script">AltOS Map CGI Script</h3>
70 <div class="paragraph">
71 <p>The AltOS Map CGI Script is a straightforward script which connects to
72 the AltOS Map Cache Manager, transmits a URL describing the desired
73 map tile and receives back a filename (or error), then sends the
74 contents of that file back through Apache to the requesting
75 application. The name of the script is 'altos-map'.</p>
76 </div>
77 <div class="sect3">
78 <h4 id="_inputs">Inputs</h4>
79 <div class="paragraph">
80 <p>The AltOS Map CGI Script will parse the provided AltOS Map URI or
81 AltOS Version URI.</p>
82 </div>
83 </div>
84 <div class="sect3">
85 <h4 id="_outputs">Outputs</h4>
86 <div class="paragraph">
87 <p>For AltOS Map URLs, the CGI Script will return either the contents of
88 the associated Google Map tile or an error indicating what failed:</p>
89 </div>
90 <div class="paragraph">
91 <p><em>200 OK</em>: The map tile image data or version information</p>
92 </div>
93 <div class="paragraph">
94 <p><em>400 Bad Request</em>: The URL is malformed or not compatible with the
95 version supported by the service</p>
96 </div>
97 <div class="paragraph">
98 <p><em>403 Forbidden</em>: The map tile is outside the areas supported by the
99 current AltOS Map service area</p>
100 </div>
101 <div class="paragraph">
102 <p><em>408 Request Timeout</em>: Attempts to fetch the tile from Google Maps
103 timed out.</p>
104 </div>
105 <div class="paragraph">
106 <p><em>503 Service Unavailable</em>: The service is temporarily refusing to
107 satisfy this request due to resource limitations.</p>
108 </div>
109 </div>
110 </div>
111 <div class="sect2">
112 <h3 id="_altos_map_cache_manager">AltOS Map Cache Manager</h3>
113 <div class="paragraph">
114 <p>This is a service running on the local machine and available over a
115 local network socket. It translates an AltOS Map URL into a local
116 filename containing the contents of the associated Google Maps
117 tile. The name of the cache manager is 'altos-mapd'. It will listen
118 for requests on port 16717.</p>
119 </div>
120 </div>
121 <div class="sect2">
122 <h3 id="_altos_map_uri">AltOS Map URI</h3>
123 <div class="paragraph">
124 <p>AltOS uses a limited subset of the Google Maps, and the AltOS Map URIs
125 only encode those elements which we currently use. This specification
126 describes AltOS Map URI format version 1.0.0. The application is
127 required to provide URIs compatible with the format supported by the
128 server. The elements of the  elements are:</p>
129 </div>
130 <div class="ulist">
131 <ul>
132 <li>
133 <p>Latitude of center point</p>
134 </li>
135 <li>
136 <p>Longitude of center point</p>
137 </li>
138 <li>
139 <p>Zoom level (from bushes to planets)</p>
140 </li>
141 </ul>
142 </div>
143 <div class="paragraph">
144 <p>Encoding this in a URI is straightforward:</p>
145 </div>
146 <div class="literalblock">
147 <div class="content">
148 <pre>altos-map?lat=&lt;lat&gt;&amp;lon=&lt;lon&gt;&amp;zoom=&lt;zoom&gt;</pre>
149 </div>
150 </div>
151 <div class="paragraph">
152 <p>Latitude and longitude are both encoded using decimal degrees with 6
153 digits following the decimal point.</p>
154 </div>
155 <div class="paragraph">
156 <p>Zoom levels can range from 1 (world) to 20 (buildings). Higher zoom
157 levels show smaller areas at greater detail.</p>
158 </div>
159 <div class="paragraph">
160 <p>The only Google Map type supported by version 1.0.0 of the service is
161 “hybrid”, which combines road graphics on top of satellite images.</p>
162 </div>
163 <div class="paragraph">
164 <p>Version 1.0.0 always returns images which are 512x512 pixels.</p>
165 </div>
166 <div class="paragraph">
167 <p>If we need additional elements in the URL, we can add them in the
168 future and bump the supported version number.</p>
169 </div>
170 </div>
171 <div class="sect2">
172 <h3 id="_altos_version_uri">AltOS Version URI</h3>
173 <div class="paragraph">
174 <p>To allow applications to discover what AltOS Map URI version is supported by the
175 AltOS Map service, the application may query the version of the API
176 supported using the Version URI. The application provides the version
177 that it supports and the AltOS Map service returns a version not
178 greater than the client version:</p>
179 </div>
180 <div class="literalblock">
181 <div class="content">
182 <pre>altos-map?version=&lt;client-major&gt;.&lt;client-minor&gt;.&lt;client-revision&gt;
183
184 &lt;server-major&gt;.&lt;server-minor&gt;.&lt;server.revision&gt;</pre>
185 </div>
186 </div>
187 </div>
188 <div class="sect2">
189 <h3 id="_altos_tile_request">AltOS Tile Request</h3>
190 <div class="paragraph">
191 <p>The AltOS Map CGI Script parses the Map URI and passes that
192 information to the AltOS Map Cache Manager using the AltOS Tile
193 Specifier syntax. This is a JSON representation of the same data
194 provided by the URI:</p>
195 </div>
196 <div class="literalblock">
197 <div class="content">
198 <pre>{
199         "lat": &lt;latitude&gt;,
200         "lon": &lt;longitude&gt;,
201         "zoom": &lt;zoom-level&gt;,
202         "remote_addr": "&lt;IPv4 or IPv6 address of requesting client&gt;"
203 }</pre>
204 </div>
205 </div>
206 <div class="paragraph">
207 <p>Latitude and longitude are both encoded using decimal degrees with 6
208 digits following the decimal point.</p>
209 </div>
210 </div>
211 <div class="sect2">
212 <h3 id="_altos_tile_reply">AltOS Tile Reply</h3>
213 <div class="paragraph">
214 <p>Sent back from the Cache Manager to the CGI Script, this encodes the
215 status of the request and the filename of any tile data available. It
216 is encoded in JSON format:</p>
217 </div>
218 <div class="literalblock">
219 <div class="content">
220 <pre>{
221         "status": &lt;HTTP status&gt;,
222         "filename": "&lt;absolute path to image file&gt;",
223         "content_type": "&lt;HTTP content-type&gt;"
224 }</pre>
225 </div>
226 </div>
227 <div class="paragraph">
228 <p>The “filename” and “content-type” elements are only included when
229 the status is <em>200 OK</em>.</p>
230 </div>
231 </div>
232 <div class="sect2">
233 <h3 id="_altos_tile_filename">AltOS Tile Filename</h3>
234 <div class="paragraph">
235 <p>While the current AltOS Map URI version only supports a limited subset
236 of the Google Maps functionality, we&#8217;ll encode more of that data in
237 filenames to allow for easy expansion of functionality in the
238 future. The elements of an AltOS Tile filename consist of :</p>
239 </div>
240 <div class="ulist">
241 <ul>
242 <li>
243 <p>Latitude, with N/S indicator (instead of a sign)</p>
244 </li>
245 <li>
246 <p>Longitude, with E/W indicator (instead of a sign)</p>
247 </li>
248 <li>
249 <p>Map type.</p>
250 </li>
251 <li>
252 <p>Zoom level</p>
253 </li>
254 <li>
255 <p>Scale factor. Scale, and the preceding hyphen are omitted for a scale factor of 1.</p>
256 </li>
257 <li>
258 <p>Image format suffix. '.jpg' for JPEG files and '.png' for PNG files.</p>
259 </li>
260 </ul>
261 </div>
262 <div class="paragraph">
263 <p>Latitude and longitude are both encoded using decimal degrees with 6
264 digits following the decimal point.</p>
265 </div>
266 <div class="paragraph">
267 <p>Map type is one of :</p>
268 </div>
269 <div class="paragraph">
270 <p><em>hybrid</em>: Road graphics over satellite images
271 <em>roadmap</em>: Symbolic road map
272 <em>satellite</em>: Un-annotated satellite images
273 <em>terrain</em>: Topographic map</p>
274 </div>
275 <div class="paragraph">
276 <p>Here&#8217;s what map filenames look like:</p>
277 </div>
278 <div class="literalblock">
279 <div class="content">
280 <pre>map-{N,S}&lt;lat&gt;,{E,W}&lt;lon&gt;-&lt;type&gt;-&lt;zoom&gt;[-&lt;scale&gt;].&lt;format&gt;</pre>
281 </div>
282 </div>
283 <div class="literalblock">
284 <div class="content">
285 <pre>map-N36.508532,W107.823944-hybrid-18.jpg</pre>
286 </div>
287 </div>
288 <div class="paragraph">
289 <p>To transmit this name from the AltOS Map Cache Manager back to the
290 Altos Map CGI script, the filename will be wrapped in a JSON string</p>
291 </div>
292 </div>
293 </div>
294 </div>
295 <div class="sect1">
296 <h2 id="_implementation">Implementation</h2>
297 <div class="sectionbody">
298 <div class="paragraph">
299 <p>The AltOS Map CGI Script and AltOS Map Cache Manager will both be
300 implemented in Java as much of the required Google Maps infrastructure
301 is already available in that language.</p>
302 </div>
303 <div class="sect2">
304 <h3 id="_access_control">Access Control</h3>
305 <div class="paragraph">
306 <p>No access control to the service is planned at this point. If
307 necessary, we could implement username/password access control for each
308 user of the service.</p>
309 </div>
310 </div>
311 <div class="sect2">
312 <h3 id="_location_restrictions">Location Restrictions</h3>
313 <div class="paragraph">
314 <p>To avoid unbounded usage, and confine the utility of this service to
315 AltOS users, the service will only offer map tiles whose center
316 location is within 10 miles of one of the sites registered in
317 our launch sites database.</p>
318 </div>
319 <div class="paragraph">
320 <p>To allow testing of the registered launch site database, a database of
321 privileged clients will be supported. Privileged clients will have
322 unlimited access to the service.</p>
323 </div>
324 </div>
325 <div class="sect2">
326 <h3 id="_per_client_restrictions">Per-Client Restrictions</h3>
327 <div class="paragraph">
328 <p>We should implement a per-day limit on the number of tiles provided to
329 a particular requesting client. We can also rate limit clients to a
330 certain number of tiles per minute to reduce the bandwidth consumed
331 out of our server.</p>
332 </div>
333 </div>
334 <div class="sect2">
335 <h3 id="_cache_lifetime_restrictions">Cache Lifetime Restrictions.</h3>
336 <div class="paragraph">
337 <p>The Google Maps API allows for caching of map data for no more than 30
338 days. To honor this, the Cache Manager will re-fetch any requested
339 tiles when the cached version is older than this. If the fetch fails,
340 the cache manager will continue to serve the data from the cached
341 version of the file.</p>
342 </div>
343 </div>
344 </div>
345 </div>
346 </div>
347 <div id="footer">
348 <div id="footer-text">
349 Last updated 2019-06-05 10:39:17 -0600
350 </div>
351 </div>
352 </body>
353 </html>