Current section
Files
Jump to
Current section
Files
lib/wobserver/page.ex
defmodule Wobserver.Page do
@moduledoc """
Page management for custom commands and pages in api and wobserver.
"""
alias Wobserver.Page
@pages_table :wobserver_pages
@typedoc ~S"""
Accepted page formats.
"""
@type data ::
Page.t
| map
| {String.t, atom, fun}
| {String.t, atom, fun, boolean}
@typedoc ~S"""
Page structure.
Fields:
- `title`, the name of the page. Is used for the web interface menu.
- `command`, single atom to associate the page with.
- `callback`, function to be evaluated, when the a api is called or page is viewd.
The result is converted to JSON and displayed.
- `options`, map containing options for the page.
Options:
- `api_only` (`boolean`), if set to true the page won't show up in the web interface, but will only be available as API.
- `refresh` (`float`, 0-1), sets the refresh time factor. Used in the web interface to refresh the data on the page. Set to `0` for no refresh.
"""
@type t :: %__MODULE__{
title: String.t,
command: atom,
callback: fun,
options: keyword,
}
defstruct [
:title,
:command,
:callback,
options: %{
api_only: false,
refresh: 1,
},
]
@doc ~S"""
List all registered pages.
For every page the following information is given:
- `title`
- `command`
- `api_only`
- `refresh`
"""
@spec list :: list(map)
def list do
ensure_table()
@pages_table
|> :ets.match(:"$1")
|> Enum.map(fn [{command, %Page{title: title, options: options}}] ->
%{
title: title,
command: command,
api_only: options.api_only,
refresh: options.refresh,
}
end)
end
@doc ~S"""
Find the page for a given `command`
Returns `:page_not_found`, if no page can be found.
"""
@spec find(command :: atom) :: Page.t
def find(command) do
ensure_table()
case :ets.lookup(@pages_table, command) do
[{^command, page}] -> page
_ -> :page_not_found
end
end
@doc ~S"""
Calls the function associated with the `command`/page.
Returns the result of the function or `:page_not_found`, if the page can not be found.
"""
@spec call(Page.t | atom) :: any
def call(:page_not_found), do: :page_not_found
def call(%Page{callback: callback}), do: callback.()
def call(command) when is_atom(command), do: command |> find() |> call()
def call(_), do: :page_not_found
@doc ~S"""
Registers a `page` with `:wobserver`.
Returns true if succesfully added. (otherwise false)
The following inputs are accepted:
- `{title, command, callback}`
- `{title, command, callback, options}`
- a `map` with the following fields:
- `title`
- `command`
- `callback`
- `options` (optional)
The fields are used as followed:
- `title`, the name of the page. Is used for the web interface menu.
- `command`, single atom to associate the page with.
- `callback`, function to be evaluated, when the a api is called or page is viewd.
The result is converted to JSON and displayed.
- `options`, options for the page.
The following options can be set:
- `api_only` (`boolean`), if set to true the page won't show up in the web interface, but will only be available as API.
- `refresh` (`float`, 0-1), sets the refresh time factor. Used in the web interface to refresh the data on the page. Set to `0` for no refresh.
"""
@spec register(page :: Page.data) :: boolean
def register(page)
def register({title, command, callback}),
do: register(title, command, callback)
def register({title, command, callback, options}),
do: register(title, command, callback, options)
def register(page = %Page{}) do
ensure_table()
:ets.insert @pages_table, {page.command, page}
end
def register(%{title: t, command: command, callback: call, options: options}),
do: register(t, command, call, options)
def register(%{title: title, command: command, callback: callback}),
do: register(title, command, callback)
def register(_), do: false
@doc ~S"""
Registers a `page` with `:wobserver`.
The arguments are used as followed:
- `title`, the name of the page. Is used for the web interface menu.
- `command`, single atom to associate the page with.
- `callback`, function to be evaluated, when the a api is called or page is viewd.
The result is converted to JSON and displayed.
- `options`, options for the page.
The following options can be set:
- `api_only` (`boolean`), if set to true the page won't show up in the web interface, but will only be available as API.
- `refresh` (`float`, 0-1), sets the refresh time factor. Used in the web interface to refresh the data on the page. Set to `0` for no refresh.
"""
@spec register(
title :: String.t,
command :: atom,
callback :: fun,
options :: keyword
) :: boolean
def register(title, command, callback, options \\ []) do
register(%Page{
title: title,
command: command,
callback: callback,
options: %{
api_only: Keyword.get(options, :api_only, false),
refresh: Keyword.get(options, :refresh, 1.0)
},
})
end
@doc ~S"""
Loads custom pages from configuration and adds them to `:wobserver`.
To add custom pages set the `:pages` option.
The `:pages` option must be a list of page data.
The page data can be formatted as:
- `{title, command, callback}`
- `{title, command, callback, options}`
- a `map` with the following fields:
- `title`
- `command`
- `callback`
- `options` (optional)
For more information and types see: `Wobserver.Page.register/1`.
Example:
```elixir
config :wobserver,
pages: [
{"Example", :example, fn -> %{x: 9} end}
]
```
"""
@spec load_config :: [any]
def load_config do
ensure_table()
:wobserver
|> Application.get_env(:pages, [])
|> Enum.map(®ister/1)
end
# Helpers
defp ensure_table do
case :ets.info(@pages_table) do
:undefined ->
:ets.new @pages_table, [:named_table, :public]
true
_ ->
true
end
end
end