geo_code_repo.rb

 1# frozen_string_literal: true
 2
 3require "cbor"
 4require "json"
 5
 6require_relative "geo_code"
 7
 8class GeoCodeRepo
 9	def initialize(memcache: MEMCACHE)
10		@memcache = memcache
11	end
12
13	# @param q [String]
14	# @return [EMPromise<GeoCode>]
15	def find(q)
16		req(q, locate: q)
17	end
18
19	# @param lat [Float]
20	# @param lon [Float]
21	# @return [EMPromise<GeoCode>]
22	def reverse(lat, lon)
23		req("reverse_#{lat}_#{lon}", latt: lat, longt: lon)
24	end
25
26protected
27
28	# @param cache_key [String]
29	# @param query [Hash]
30	# @return [EMPromise<GeoCode>]
31	def req(cache_key, **query)
32		cache(cache_key) {
33			EM::HttpRequest.new(
34				"https://geocoder.ca/",
35				tls: { verify_peer: true }
36			).aget(query: { json: 1, **query }).then { |res|
37				json = JSON.parse(res.response)
38				raise "Geocode Failure" unless json["latt"] && json["longt"]
39
40				json
41			}
42		}.then(&GeoCode.method(:for))
43	end
44
45	def cache(k, &blk)
46		k = "geocode_#{k.gsub(/ /, '%20')}"
47		promise = EMPromise.new
48		@memcache.get(k, &promise.method(:fulfill))
49		promise.then { |cbor|
50			CBOR.decode(cbor)
51		}.catch(&blk).then { |result|
52			@memcache.set(k, result.to_cbor)
53			result
54		}
55	end
56end