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