summaryrefslogtreecommitdiff
path: root/lib/plugins/helpers/temp_ref.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins/helpers/temp_ref.ex')
-rw-r--r--lib/plugins/helpers/temp_ref.ex95
1 files changed, 95 insertions, 0 deletions
diff --git a/lib/plugins/helpers/temp_ref.ex b/lib/plugins/helpers/temp_ref.ex
new file mode 100644
index 0000000..160169d
--- /dev/null
+++ b/lib/plugins/helpers/temp_ref.ex
@@ -0,0 +1,95 @@
+defmodule Nola.Plugins.TempRefHelper do
+ @moduledoc """
+ This module allows to easily implement local temporary simple references for easy access from IRC.
+
+ For example, your plugin output could be acted on, and instead of giving the burden for the user to
+ write or copy that uuid, you could give them a small alphanumeric reference to use instead.
+
+ You can configure how many and for how long the references are kept.
+
+ ## Usage
+
+ `import Irc.Plugin.TempRef`
+
+ ```elixir
+ defmodule Irc.MyPlugin do
+ defstruct [:temprefs]
+
+ def init(_) do
+ # …
+ {:ok, %__MODULE__{temprefs: new_temp_refs()}
+ end
+ end
+ ```
+ """
+
+ defstruct [:refs, :max, :expire, :build_fun, :build_increase_fun, :build_options]
+
+ defmodule SimpleAlphaNumericBuilder do
+ def build(options) do
+ length = Keyword.get(options, :length, 3)
+ for _ <- 1..length, into: "", do: <<Enum.random('bcdfghjkmpqtrvwxy2346789')>>
+ end
+
+ def increase(options) do
+ Keyword.put(options, :length, Keyword.get(options, :length, 3) + 1)
+ end
+ end
+
+ def new_temp_refs(options \\ []) do
+ %__MODULE__{
+ refs: Keyword.get(options, :init_refs, []),
+ max: Keyword.get(options, :max, []),
+ expire: Keyword.get(options, :expire, :infinity),
+ build_fun: Keyword.get(options, :build_fun, &__MODULE__.SimpleAlphaNumericBuilder.build/1),
+ build_increase_fun: Keyword.get(options, :build_increase_fun, &__MODULE__.SimpleAlphaNumericBuilder.increase/1),
+ build_options: Keyword.get(options, :build_options, [length: 3])
+ }
+ end
+
+ def janitor_refs(state = %__MODULE__{}) do
+ if length(state.refs) > state.max do
+ %__MODULE__{refs: state.refs |> Enum.reverse() |> tl() |> Enum.reverse()}
+ else
+ state
+ end
+ end
+
+ def put_temp_ref(data, state = %__MODULE__{}) do
+ state = janitor_refs(state)
+ key = new_nonexisting_key(state)
+ if key do
+ ref = {key, DateTime.utc_now(), data}
+ {key, %__MODULE__{state | refs: [ref | state.refs]}}
+ else
+ {nil, state}
+ end
+ end
+
+ def lookup_temp_ref(key, state, default \\ nil) do
+ case List.keyfind(state.refs, key, 0) do
+ {_, _, data} -> data
+ _ -> default
+ end
+ end
+
+ defp new_nonexisting_key(state, i) when i > 50 do
+ nil
+ end
+
+ defp new_nonexisting_key(state = %__MODULE__{refs: refs}, i \\ 1) do
+ build_options = if rem(i, 5) == 0 do
+ state.build_increase_fun.(state.build_options)
+ else
+ state.build_options
+ end
+
+ key = state.build_fun.(state.build_options)
+ if !List.keymember?(refs, key, 0) do
+ key
+ else
+ new_nonexisting_key(state, i + 1)
+ end
+ end
+
+end