|
1 |
| -defmodule Tz.UpdatePeriodically do |
2 |
| - use GenServer |
| 1 | +if Code.ensure_loaded?(Mint.HTTP) do |
| 2 | + defmodule Tz.UpdatePeriodically do |
| 3 | + use GenServer |
3 | 4 |
|
4 |
| - require Logger |
| 5 | + require Logger |
5 | 6 |
|
6 |
| - alias Tz.Compiler |
7 |
| - alias Tz.PeriodsProvider |
8 |
| - alias Tz.HTTP.HTTPClient |
9 |
| - alias Tz.HTTP.HTTPResponse |
| 7 | + alias Tz.Compiler |
| 8 | + alias Tz.PeriodsProvider |
| 9 | + alias Tz.HTTP.HTTPClient |
| 10 | + alias Tz.HTTP.HTTPResponse |
10 | 11 |
|
11 |
| - def start_link(_) do |
12 |
| - unless Code.ensure_loaded?(Mint.HTTP) do |
13 |
| - raise "Add mint to mix.exs to enable automatic time zone data updates" |
| 12 | + def start_link(_) do |
| 13 | + GenServer.start_link(__MODULE__, %{}) |
14 | 14 | end
|
15 | 15 |
|
16 |
| - GenServer.start_link(__MODULE__, %{}) |
17 |
| - end |
| 16 | + def init(state) do |
| 17 | + schedule_work() |
| 18 | + {:ok, state} |
| 19 | + end |
18 | 20 |
|
19 |
| - def init(state) do |
20 |
| - schedule_work() |
21 |
| - {:ok, state} |
22 |
| - end |
| 21 | + def handle_info(:work, state) do |
| 22 | + Logger.debug("Tz is checking for IANA time zone database updates") |
23 | 23 |
|
24 |
| - def handle_info(:work, state) do |
25 |
| - Logger.debug("Tz is checking for IANA time zone database updates") |
| 24 | + if maybe_update_tz_database() == :updated do |
| 25 | + Logger.info("Tz is recompiling time zone periods...") |
| 26 | + Code.compiler_options(ignore_module_conflict: true) |
| 27 | + Compiler.compile() |
| 28 | + Code.compiler_options(ignore_module_conflict: false) |
| 29 | + Logger.info("Tz compilation done") |
| 30 | + end |
26 | 31 |
|
27 |
| - if maybe_update_tz_database() == :updated do |
28 |
| - Logger.info("Tz is recompiling time zone periods...") |
29 |
| - Code.compiler_options(ignore_module_conflict: true) |
30 |
| - Compiler.compile() |
31 |
| - Code.compiler_options(ignore_module_conflict: false) |
32 |
| - Logger.info("Tz compilation done") |
| 32 | + schedule_work() |
| 33 | + {:noreply, state} |
33 | 34 | end
|
34 | 35 |
|
35 |
| - schedule_work() |
36 |
| - {:noreply, state} |
37 |
| - end |
38 |
| - |
39 |
| - defp schedule_work() do |
40 |
| - Process.send_after(self(), :work, 24 * 60 * 60 * 1000) # In 24 hours |
41 |
| - end |
| 36 | + defp schedule_work() do |
| 37 | + Process.send_after(self(), :work, 24 * 60 * 60 * 1000) # In 24 hours |
| 38 | + end |
42 | 39 |
|
43 |
| - defp maybe_update_tz_database() do |
44 |
| - case fetch_iana_tz_version() do |
45 |
| - {:ok, latest_version} -> |
46 |
| - if latest_version != PeriodsProvider.version() do |
47 |
| - case update_tz_database(latest_version) do |
48 |
| - :ok -> |
49 |
| - delete_tz_database(PeriodsProvider.version()) |
50 |
| - :updated |
51 |
| - _ -> :error |
| 40 | + defp maybe_update_tz_database() do |
| 41 | + case fetch_iana_tz_version() do |
| 42 | + {:ok, latest_version} -> |
| 43 | + if latest_version != PeriodsProvider.version() do |
| 44 | + case update_tz_database(latest_version) do |
| 45 | + :ok -> |
| 46 | + delete_tz_database(PeriodsProvider.version()) |
| 47 | + :updated |
| 48 | + _ -> :error |
| 49 | + end |
52 | 50 | end
|
53 |
| - end |
54 |
| - :error -> |
55 |
| - Logger.error("Tz failed to read the latest version of the IANA time zone database") |
56 |
| - :no_update |
| 51 | + :error -> |
| 52 | + Logger.error("Tz failed to read the latest version of the IANA time zone database") |
| 53 | + :no_update |
| 54 | + end |
57 | 55 | end
|
58 |
| - end |
59 | 56 |
|
60 |
| - defp fetch_iana_tz_version() do |
61 |
| - case HTTPClient.request("GET", "/time-zones/tzdb/version", hostname: "data.iana.org") do |
62 |
| - %HTTPResponse{body: body, status_code: 200} -> |
63 |
| - {:ok, body |> List.first() |> String.trim()} |
64 |
| - _ -> |
65 |
| - :error |
| 57 | + defp fetch_iana_tz_version() do |
| 58 | + case HTTPClient.request("GET", "/time-zones/tzdb/version", hostname: "data.iana.org") do |
| 59 | + %HTTPResponse{body: body, status_code: 200} -> |
| 60 | + {:ok, body |> List.first() |> String.trim()} |
| 61 | + _ -> |
| 62 | + :error |
| 63 | + end |
66 | 64 | end
|
67 |
| - end |
68 | 65 |
|
69 |
| - defp update_tz_database(version) do |
70 |
| - case download_tz_database(version) do |
71 |
| - {:ok, content} -> |
72 |
| - extract_tz_database(version, content) |
73 |
| - :ok |
74 |
| - :error -> |
75 |
| - Logger.error("Tz failed to download the latest archived IANA time zone database (version #{version})") |
76 |
| - :error |
| 66 | + defp update_tz_database(version) do |
| 67 | + case download_tz_database(version) do |
| 68 | + {:ok, content} -> |
| 69 | + extract_tz_database(version, content) |
| 70 | + :ok |
| 71 | + :error -> |
| 72 | + Logger.error("Tz failed to download the latest archived IANA time zone database (version #{version})") |
| 73 | + :error |
| 74 | + end |
77 | 75 | end
|
78 |
| - end |
79 | 76 |
|
80 |
| - defp download_tz_database(version) do |
81 |
| - Logger.info("Tz is downloading the latest IANA time zone database (version #{version})...") |
82 |
| - case HTTPClient.request("GET", "/time-zones/releases/tzdata#{version}.tar.gz", hostname: "data.iana.org") do |
83 |
| - %HTTPResponse{body: body, status_code: 200} -> |
84 |
| - Logger.info("Tz download done") |
85 |
| - {:ok, body} |
86 |
| - _ -> |
87 |
| - :error |
| 77 | + defp download_tz_database(version) do |
| 78 | + Logger.info("Tz is downloading the latest IANA time zone database (version #{version})...") |
| 79 | + case HTTPClient.request("GET", "/time-zones/releases/tzdata#{version}.tar.gz", hostname: "data.iana.org") do |
| 80 | + %HTTPResponse{body: body, status_code: 200} -> |
| 81 | + Logger.info("Tz download done") |
| 82 | + {:ok, body} |
| 83 | + _ -> |
| 84 | + :error |
| 85 | + end |
88 | 86 | end
|
89 |
| - end |
90 | 87 |
|
91 |
| - defp extract_tz_database(version, content) do |
92 |
| - tmp_archive_path = Path.join(:code.priv_dir(:tz), "tzdata#{version}.tar.gz") |
93 |
| - tz_data_dir = "tzdata#{version}" |
94 |
| - :ok = File.write!(tmp_archive_path, content) |
95 |
| - :ok = :erl_tar.extract(tmp_archive_path, [:compressed, {:cwd, Path.join(:code.priv_dir(:tz), tz_data_dir)}]) |
96 |
| - :ok = File.rm!(tmp_archive_path) |
97 |
| - end |
| 88 | + defp extract_tz_database(version, content) do |
| 89 | + tmp_archive_path = Path.join(:code.priv_dir(:tz), "tzdata#{version}.tar.gz") |
| 90 | + tz_data_dir = "tzdata#{version}" |
| 91 | + :ok = File.write!(tmp_archive_path, content) |
| 92 | + :ok = :erl_tar.extract(tmp_archive_path, [:compressed, {:cwd, Path.join(:code.priv_dir(:tz), tz_data_dir)}]) |
| 93 | + :ok = File.rm!(tmp_archive_path) |
| 94 | + end |
98 | 95 |
|
99 |
| - defp delete_tz_database(version) do |
100 |
| - Path.join(:code.priv_dir(:tz), "tzdata#{version}") |
101 |
| - |> File.rm_rf!() |
| 96 | + defp delete_tz_database(version) do |
| 97 | + Path.join(:code.priv_dir(:tz), "tzdata#{version}") |
| 98 | + |> File.rm_rf!() |
| 99 | + end |
102 | 100 | end
|
103 | 101 | end
|
0 commit comments