lib/cos/utils.ex

defmodule COS.Utils do
  @type expire_in :: pos_integer() | {pos_integer(), :second | :minute | :hour | :day}

  @doc """
  将驼峰 key 转换为下划线风格
  """
  @spec underscore_keys(value :: any()) :: any()
  def underscore_keys(map) when is_map(map) do
    Map.new(map, fn {key, value} -> {Macro.underscore(key), underscore_keys(value)} end)
  end

  def underscore_keys(list) when is_list(list) do
    Enum.map(list, &underscore_keys/1)
  end

  def underscore_keys(other), do: other

  @doc """
  根据 {amount, unit} 格式计算出多少秒
  """
  @spec to_seconds(expire_in :: expire_in()) :: pos_integer()
  def to_seconds(seconds) when is_integer(seconds), do: seconds
  def to_seconds({seconds, :second}), do: to_seconds(seconds)
  def to_seconds({minutes, :minute}), do: to_seconds(minutes * 60)
  def to_seconds({hours, :hour}), do: to_seconds(hours * 60 * 60)
  def to_seconds({days, :day}), do: to_seconds(days * 24 * 60 * 60)

  @doc """
  对特殊符号进行编码 - [腾讯云文档](https://cloud.tencent.com/document/product/436/7778#.E5.87.86.E5.A4.87.E5.B7.A5.E4.BD.9C)
  """
  @spec url_encode(value :: binary() | integer()) :: binary()
  def url_encode(value) do
    value |> to_string() |> URI.encode_www_form() |> String.replace("+", "%20")
  end

  # TODO: remove when we require OTP 22.1
  if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :mac, 4) do
    def hmac(sub_type, key, data), do: :crypto.mac(:hmac, sub_type, key, data)
  else
    def hmac(sub_type, key, data), do: :crypto.hmac(sub_type, key, data)
  end
end