defmodule Imglab do
@moduledoc """
Provides a set of functions to work with imglab services.
"""
alias Imglab.Source
alias Imglab.Signature
alias Imglab.Utils
@doc """
Returns a formatted URL `string` with the specified parameters.
* `source_name_or_source` must be a `string` indicating a source name or a [Source struct](`t:Imglab.Source.t/0`).
* `path` must be a `string` indicating the path of the resource.
* `params` must be an optional `keyword` list with the image parameters to use.
## Source
The first parameter can be a `string` with the name of the source in the case that no additional settings for the source are needed:
iex> Imglab.url("assets", "image.jpeg", width: 500, height: 600)
"https://cdn.imglab.io/assets/image.jpeg?width=500&height=600"
Or a [Source struct](`t:Imglab.Source.t/0`) created with `Imglab.Source.new/2` specifying additional settings for the source if needed:
iex> "assets"
iex> |> Imglab.Source.new()
iex> |> Imglab.url("image.jpeg", width: 500, height: 600)
"https://cdn.imglab.io/assets/image.jpeg?width=500&height=600"
### Secured sources
You can specify a secure source and use it to generate signed URLs:
iex> "assets"
iex> |> Imglab.Source.new(secure_key: "qxxKNvxRONOMklcGJBVczefrJnE=", secure_salt: "e9bXw6/HIMGTWcmAYArHA5jpIAE=")
iex> |> Imglab.url("image.jpeg", width: 500, height: 600)
"https://cdn.imglab.io/assets/image.jpeg?width=500&height=600&signature=MX0DlvzVo39-_Dh_YqPbOnrayWVabIWaSDzi-9PfGHQ"
The `signature` query string will be automatically added to the URL.
> Note: `secure_key` and `secure_salt` paramaters are secrets that should not be added to the code. Please use environment vars or other secure method to use them in your project.
## Path
The second parameter must be a `string` defining the path to the resource.
iex> Imglab.url("assets", "path/to/myimage.jpeg", width: 500, height: 600)
"https://cdn.imglab.io/assets/path/to/myimage.jpeg?width=500&height=600"
## Params
The third optional parameter is a `keyword` list with any desired imglab transformation parameter.
Some imglab parameters use hyphens inside their names. You can use atoms with underscores, these will be normalized to the correct format used by imglab API.
iex> Imglab.url("assets", "image.jpeg", width: 500, trim: "color", trim_color: "orange")
"https://cdn.imglab.io/assets/image.jpeg?width=500&trim=color&trim-color=orange"
Or you can define a quoted atom instead:
iex> Imglab.url("assets", "image.jpeg", width: 500, trim: "color", "trim-color": "orange")
"https://cdn.imglab.io/assets/image.jpeg?width=500&trim=color&trim-color=orange"
If no params are specified a URL without query params will be generated:
iex> Imglab.url("assets", "image.jpeg")
"https://cdn.imglab.io/assets/image.jpeg"
"""
@spec url(binary | Source.t(), binary, keyword) :: binary
def url(source_name_or_source, path, params \\ [])
def url(source_name, path, params) when is_binary(source_name) and is_binary(path) and is_list(params) do
url(Source.new(source_name), path, params)
end
def url(%Source{} = source, path, params) when is_binary(path) and is_list(params) do
normalized_path = Utils.normalize_path(path)
normalized_params = Utils.normalize_params(params)
URI.to_string(%URI{
scheme: Source.scheme(source),
host: Source.host(source),
port: source.port,
path: Path.join("/", Source.path(source, normalized_path)),
query: encode_params(source, normalized_path, normalized_params)
})
end
@spec encode_params(Source.t(), binary, list) :: binary
defp encode_params(%Source{} = source, path, params)
when is_binary(path) and is_list(params) and length(params) > 0 do
if Source.secure?(source) do
signature = Signature.generate(source, path, URI.encode_query(params))
URI.encode_query(params ++ [{"signature", signature}])
else
URI.encode_query(params)
end
end
defp encode_params(%Source{} = source, path, _params) when is_binary(path) do
if Source.secure?(source) do
signature = Signature.generate(source, path)
URI.encode_query(signature: signature)
else
nil
end
end
end