Skip to content

Instantly share code, notes, and snippets.

@eidge
Last active June 27, 2016 12:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eidge/087d2b5527293ffaeb9303178bc07801 to your computer and use it in GitHub Desktop.
Save eidge/087d2b5527293ffaeb9303178bc07801 to your computer and use it in GitHub Desktop.
defmodule Weather.NOAA.Forecast do
@moduledoc """
Implements primitives to download forecasts from the NOAA servers.
"""
defstruct params: nil, data: :not_computed, format: :grib2
@type t :: %__MODULE__{
params: nil | Params.t,
format: :grib2,
data: nil | binary
}
alias Weather.NOAA.Forecast.Params
alias Weather.NOAA.Forecast.PathBuilder
alias HTTPotion.Response
@doc """
Downloads a grib2 forecast given a model name and an optional list of options.
Args:
- params - Forecast params to fetch, Weather.NOAA.ForecastParams.t
- options - Keyword.t
options:
- timeout - timeout in ms, integer | :infinity (default: 20000)
"""
def get(%Params{} = params, options \\ []) do
http_options = Keyword.merge([timeout: 20000], options)
file_url = PathBuilder.path_for(params)
case fetch(file_url, http_options) do
{:ok, forecast_grib2} -> {:ok, build_forecast(params, forecast_grib2)}
{:error, explanation} -> {:error, explanation}
end
end
defp build_forecast(params, grib2) do
%__MODULE__{
params: params,
data: grib2
}
end
@doc """
Fetches a list of available forecast cycles from NOAA
Args:
- model_name - atom (see Forecast.PathBuilder.directory_path_for/1)
- options - Keyword.t
options:
- timeout - timeout in ms, integer | :infinity (default: 20000)
"""
def available_cycles(model_name, options \\ []) do
file_url = PathBuilder.directory_path_for(model_name)
case fetch(file_url, options) do
{:ok, cycles_html} -> {:ok, DirectoryListingHTMLParser.cycles(cycles_html)}
{:error, explanation} -> {:error, explanation}
end
end
defp fetch(url, options) do
try do
case HTTPotion.get(url, options) do
%Response{status_code: 200, body: body} -> {:ok, body}
%Response{status_code: status, body: error} -> {:error, {status, error}}
end
rescue
e in HTTPotion.HTTPError ->
if e.message == "req_timedout" do
{:error, :timeout}
else
raise e
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment