Current section
Files
Jump to
Current section
Files
lib/parser.ex
defmodule DS.Parser do
@moduledoc """
Parser module, which looks for cached value. If is not found, parses user agent by UAInspector (https://github.com/elixytics/ua_inspector)
"""
@mobile_device_types ["smartphone", "tablet", "phablet", "feature phone"]
@doc """
Parses user agent
"""
@spec parse(DS.ua()) :: DS.t() | nil
def parse(""), do: nil
def parse(nil), do: nil
def parse(ua) do
ua
|> check_cache()
|> do_parse()
end
defp check_cache(ua) do
case :ets.lookup(:ds_cache, generate_key(ua)) do
[] -> {:error, ua}
[{_, result}] -> {:ok, result}
end
end
defp do_parse({:ok, ds}), do: ds
defp do_parse({:error, ua}) do
ds =
ua
|> UAInspector.parse()
|> assemble_client()
|> assemble_device()
|> assemble_os()
key = generate_key(ua)
:ets.insert(:ds_cache, {key, ds})
ds
end
defp assemble_client(%{client: :unknown}) do
%DS{
device_type: "desktop"
}
end
defp assemble_client(%UAInspector.Result.Bot{name: name}) do
%DS{
is_bot?: true,
bot_name: name
}
end
defp assemble_client(%{client: client} = result) do
ds = %DS{
browser: client.name,
browser_version: client.version
}
Map.new(ds: ds, result: result)
end
defp assemble_device(%DS{} = ds), do: ds
defp assemble_device(%{ds: ds, result: %{device: device} = result}) do
%{
ds: %{
ds
| device_type: to_string(device.type),
device_brand: to_string(device.brand),
device_model: to_string(device.model),
is_mobile?: device.type in @mobile_device_types
},
result: result
}
end
defp assemble_os(%DS{} = ds), do: ds
defp assemble_os(%{ds: ds, result: %{os: os}}) do
%{ds | os: os.name, os_version: to_string(os.version)}
end
defp generate_key(ua), do: Base.encode16(:crypto.hash(:md5, ua), case: :lower)
end