summaryrefslogtreecommitdiff
path: root/lib/nola
diff options
context:
space:
mode:
authorJordan Bracco <href@random.sh>2025-06-25 19:22:59 +0200
committerJordan Bracco <href@random.sh>2025-06-25 19:22:59 +0200
commitc934e79e5852e05f714b2d542cc2678e287c49b8 (patch)
tree55779a0168260fce03e4775eacdd613ffc945588 /lib/nola
parentupdates (diff)
format.
Diffstat (limited to 'lib/nola')
-rw-r--r--lib/nola/account.ex58
-rw-r--r--lib/nola/auth_token.ex21
-rw-r--r--lib/nola/icecast.ex100
-rw-r--r--lib/nola/icecast_agent.ex6
-rw-r--r--lib/nola/membership.ex43
-rw-r--r--lib/nola/message.ex21
-rw-r--r--lib/nola/plugins.ex44
-rw-r--r--lib/nola/subnet.ex67
-rw-r--r--lib/nola/token.ex24
-rw-r--r--lib/nola/trigger.ex1
-rw-r--r--lib/nola/user_track.ex323
11 files changed, 465 insertions, 243 deletions
diff --git a/lib/nola/account.ex b/lib/nola/account.ex
index 70e9e40..d850a82 100644
--- a/lib/nola/account.ex
+++ b/lib/nola/account.ex
@@ -44,7 +44,7 @@ defmodule Nola.Account do
end
def start_link() do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_) do
@@ -63,6 +63,7 @@ defmodule Nola.Account do
def get_by_name(name) do
spec = [{{:_, :"$1", :_}, [{:==, :"$1", {:const, name}}], [:"$_"]}]
+
case :dets.select(file("db"), spec) do
[account] -> from_tuple(account)
_ -> nil
@@ -71,7 +72,7 @@ defmodule Nola.Account do
def get_meta(%__MODULE__{id: id}, key, default \\ nil) do
case :dets.lookup(file("meta"), {id, key}) do
- [{_, value}] -> (value || default)
+ [{_, value}] -> value || default
_ -> default
end
end
@@ -86,8 +87,12 @@ defmodule Nola.Account do
@doc "Find an account given a specific meta `key` and `value`."
@spec find_meta_account(String.t(), String.t()) :: t() | nil
def find_meta_account(key, value) do
- #spec = [{{{:"$1", :"$2"}, :"$3"}, [:andalso, {:==, :"$2", {:const, key}}, {:==, :"$3", {:const, value}}], [:"$1"]}]
- spec = [{{{:"$1", :"$2"}, :"$3"}, [{:andalso, {:==, :"$2", {:const, key}}, {:==, {:const, value}, :"$3"}}], [:"$1"]}]
+ # spec = [{{{:"$1", :"$2"}, :"$3"}, [:andalso, {:==, :"$2", {:const, key}}, {:==, :"$3", {:const, value}}], [:"$1"]}]
+ spec = [
+ {{{:"$1", :"$2"}, :"$3"},
+ [{:andalso, {:==, :"$2", {:const, key}}, {:==, {:const, value}, :"$3"}}], [:"$1"]}
+ ]
+
case :dets.select(file("meta"), spec) do
[id] -> get(id)
_ -> nil
@@ -100,7 +105,7 @@ defmodule Nola.Account do
end
def put_user_meta(account = %__MODULE__{}, key, value) do
- put_meta(account, "u:"<>key, value)
+ put_meta(account, "u:" <> key, value)
end
def put_meta(%__MODULE__{id: id}, key, value) do
@@ -112,15 +117,15 @@ defmodule Nola.Account do
end
def all_accounts() do
- :dets.traverse(file("db"), fn(obj) -> {:continue, from_tuple(obj)} end)
+ :dets.traverse(file("db"), fn obj -> {:continue, from_tuple(obj)} end)
end
def all_predicates() do
- :dets.traverse(file("predicates"), fn(obj) -> {:continue, obj} end)
+ :dets.traverse(file("predicates"), fn obj -> {:continue, obj} end)
end
def all_meta() do
- :dets.traverse(file("meta"), fn(obj) -> {:continue, obj} end)
+ :dets.traverse(file("meta"), fn obj -> {:continue, obj} end)
end
def merge_account(old_id, new_id) do
@@ -130,16 +135,19 @@ defmodule Nola.Account do
for pred <- predicates, do: :ok = :dets.insert(file("predicates"), {pred, new_id})
spec = [{{{:"$1", :"$2"}, :"$3"}, [{:==, :"$1", {:const, old_id}}], [{{:"$2", :"$3"}}]}]
metas = :dets.select(file("meta"), spec)
- for {k,v} <- metas do
+
+ for {k, v} <- metas do
:dets.delete(file("meta"), {{old_id, k}})
:ok = :dets.insert(file("meta"), {{new_id, k}, v})
end
+
:dets.delete(file("db"), old_id)
Nola.Membership.merge_account(old_id, new_id)
Nola.UserTrack.merge_account(old_id, new_id)
Nola.Irc.Connection.dispatch("account", {:account_change, old_id, new_id})
Nola.Irc.Connection.dispatch("conn", {:account_change, old_id, new_id})
end
+
:ok
end
@@ -150,16 +158,15 @@ defmodule Nola.Account do
@doc "Always find an account by nickname, even if offline. Uses predicates and then account name."
def find_always_by_nick(network, chan, nick) do
- with \
- nil <- find_by_nick(network, nick),
+ with nil <- find_by_nick(network, nick),
nil <- do_lookup(%User{network: network, nick: nick}, false),
- nil <- get_by_name(nick)
- do
+ nil <- get_by_name(nick) do
nil
else
%__MODULE__{} = account ->
memberships = Nola.Membership.of_account(account)
- if Enum.any?(memberships, fn({net, ch}) -> (net == network) or (chan && chan == ch) end) do
+
+ if Enum.any?(memberships, fn {net, ch} -> net == network or (chan && chan == ch) end) do
account
else
nil
@@ -173,9 +180,14 @@ defmodule Nola.Account do
def lookup(something, make_default \\ true) do
account = do_lookup(something, make_default)
+
if account && Map.get(something, :nick) do
- Nola.Irc.Connection.dispatch("account", {:account_auth, Map.get(something, :nick), account.id})
+ Nola.Irc.Connection.dispatch(
+ "account",
+ {:account_auth, Map.get(something, :nick), account.id}
+ )
end
+
account
end
@@ -198,7 +210,8 @@ defmodule Nola.Account do
end
end
- defp do_lookup(message = %Nola.Message{account: account_id}, make_default) when is_binary(account_id) do
+ defp do_lookup(message = %Nola.Message{account: account_id}, make_default)
+ when is_binary(account_id) do
get(account_id)
end
@@ -206,8 +219,12 @@ defmodule Nola.Account do
if user = Nola.UserTrack.find_by_nick(sender) do
lookup(user, make_default)
else
- #FIXME this will never work with continued lookup by other methods as Who isn't compatible
- lookup_by_nick(sender, :dets.lookup(file("predicates"), {sender.network,{:nick, sender.nick}}), make_default)
+ # FIXME this will never work with continued lookup by other methods as Who isn't compatible
+ lookup_by_nick(
+ sender,
+ :dets.lookup(file("predicates"), {sender.network, {:nick, sender.nick}}),
+ make_default
+ )
end
end
@@ -220,7 +237,7 @@ defmodule Nola.Account do
end
defp do_lookup(user = %User{network: server, nick: nick}, make_default) do
- lookup_by_nick(user, :dets.lookup(file("predicates"), {server,{:nick, nick}}), make_default)
+ lookup_by_nick(user, :dets.lookup(file("predicates"), {server, {:nick, nick}}), make_default)
end
defp do_lookup(nil, _) do
@@ -232,7 +249,7 @@ defmodule Nola.Account do
end
defp lookup_by_nick(user, _, make_default) do
- #authenticate_by_host(user)
+ # authenticate_by_host(user)
if make_default, do: new_account(user), else: nil
end
@@ -259,5 +276,4 @@ defmodule Nola.Account do
spec = [{{:"$1", :"$2"}, [{:==, :"$2", {:const, account.id}}], [:"$1"]}]
:dets.select(file("predicates"), spec)
end
-
end
diff --git a/lib/nola/auth_token.ex b/lib/nola/auth_token.ex
index 9760ec7..0da4aab 100644
--- a/lib/nola/auth_token.ex
+++ b/lib/nola/auth_token.ex
@@ -2,7 +2,7 @@ defmodule Nola.AuthToken do
use GenServer
def start_link() do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def lookup(id) do
@@ -13,6 +13,7 @@ defmodule Nola.AuthToken do
case new(account, perks) do
{:ok, id} ->
NolaWeb.Router.Helpers.login_path(NolaWeb.Endpoint, :token, id)
+
error ->
error
end
@@ -22,6 +23,7 @@ defmodule Nola.AuthToken do
case new(account, perks) do
{:ok, id} ->
NolaWeb.Router.Helpers.login_url(NolaWeb.Endpoint, :token, id)
+
error ->
error
end
@@ -32,15 +34,14 @@ defmodule Nola.AuthToken do
end
def init(_) do
- {:ok, Map.new}
+ {:ok, Map.new()}
end
def handle_call({:lookup, id}, _, state) do
IO.inspect(state)
- with \
- {account, date, perks} <- Map.get(state, id),
- d when d > 0 <- DateTime.diff(date, DateTime.utc_now())
- do
+
+ with {account, date, perks} <- Map.get(state, id),
+ d when d > 0 <- DateTime.diff(date, DateTime.utc_now()) do
{:reply, {:ok, account, perks}, Map.delete(state, id)}
else
x ->
@@ -51,9 +52,11 @@ defmodule Nola.AuthToken do
def handle_call({:new, account, perks}, _, state) do
id = Nola.UserTrack.Id.token()
- expire = DateTime.utc_now()
- |> DateTime.add(15*60, :second)
+
+ expire =
+ DateTime.utc_now()
+ |> DateTime.add(15 * 60, :second)
+
{:reply, {:ok, id}, Map.put(state, id, {account, expire, perks})}
end
-
end
diff --git a/lib/nola/icecast.ex b/lib/nola/icecast.ex
index 5a53192..021af0b 100644
--- a/lib/nola/icecast.ex
+++ b/lib/nola/icecast.ex
@@ -23,69 +23,82 @@ defmodule Nola.Icecast do
end
defp poll(state) do
- state = case request(base_url(), :get) do
- {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
- #update_json_stats(Jason.decode(body))
- stats = update_stats(body)
- if state != stats do
- Logger.info "Icecast Update: " <> inspect(stats)
- Nola.IcecastAgent.update(stats)
- Registry.dispatch(Nola.BroadcastRegistry, "icecast", fn ws ->
- for {pid, _} <- ws, do: send(pid, {:icecast, stats})
- end)
- stats
- else
+ state =
+ case request(base_url(), :get) do
+ {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
+ # update_json_stats(Jason.decode(body))
+ stats = update_stats(body)
+
+ if state != stats do
+ Logger.info("Icecast Update: " <> inspect(stats))
+ Nola.IcecastAgent.update(stats)
+
+ Registry.dispatch(Nola.BroadcastRegistry, "icecast", fn ws ->
+ for {pid, _} <- ws, do: send(pid, {:icecast, stats})
+ end)
+
+ stats
+ else
+ state
+ end
+
+ error ->
+ Logger.error("Icecast HTTP Error: #{inspect(error)}")
state
- end
- error ->
- Logger.error "Icecast HTTP Error: #{inspect error}"
- state
- end
+ end
+
interval = Application.get_env(:nola, :icecast_poll_interval, 60_000)
:timer.send_after(interval, :poll)
state
end
defp update_stats(html) do
- raw = Floki.find(html, "div.roundbox")
- |> Enum.map(fn(html) ->
- html = Floki.raw_html(html)
- [{"h3", _, ["Mount Point /"<>mount]}] = Floki.find(html, "h3.mount")
- stats = Floki.find(html, "tr")
- |> Enum.map(fn({"tr", _, tds}) ->
- [{"td", _, keys}, {"td", _, values}] = tds
- key = List.first(keys)
- value = List.first(values)
- {key, value}
+ raw =
+ Floki.find(html, "div.roundbox")
+ |> Enum.map(fn html ->
+ html = Floki.raw_html(html)
+ [{"h3", _, ["Mount Point /" <> mount]}] = Floki.find(html, "h3.mount")
+
+ stats =
+ Floki.find(html, "tr")
+ |> Enum.map(fn {"tr", _, tds} ->
+ [{"td", _, keys}, {"td", _, values}] = tds
+ key = List.first(keys)
+ value = List.first(values)
+ {key, value}
+ end)
+ |> Enum.into(Map.new())
+
+ {mount, stats}
end)
- |> Enum.into(Map.new)
- {mount, stats}
- end)
- |> Enum.into(Map.new)
+ |> Enum.into(Map.new())
live? = if Map.get(raw["live"], "Content Type:", false), do: true, else: false
- np = if live? do
- raw["live"]["Currently playing:"]
- else
- raw["autodj"]["Currently playing:"]
- end
+
+ np =
+ if live? do
+ raw["live"]["Currently playing:"]
+ else
+ raw["autodj"]["Currently playing:"]
+ end
genre = raw["live"]["Genre:"] || nil
%{np: np || "", live: live? || false, genre: genre}
end
defp update_json_stats({:ok, body}) do
- Logger.debug "JSON STATS: #{inspect body}"
+ Logger.debug("JSON STATS: #{inspect(body)}")
end
defp update_json_stats(error) do
- Logger.error "Failed to decode JSON Stats: #{inspect error}"
+ Logger.error("Failed to decode JSON Stats: #{inspect(error)}")
end
defp request(uri, method, body \\ [], headers \\ []) do
headers = [{"user-agent", "Nola-API[115ans.net, sys.115ans.net] href@random.sh"}] ++ headers
options = @httpoison_opts
- case :ok do #:fuse.ask(@fuse, :sync) do
+ # :fuse.ask(@fuse, :sync) do
+ case :ok do
:ok -> run_request(method, uri, body, headers, options)
:blown -> :blown
end
@@ -93,14 +106,18 @@ defmodule Nola.Icecast do
# This is to work around hackney's behaviour of returning `{:error, :closed}` when a pool connection has been closed
# (keep-alive expired). We just retry the request immediatly up to five times.
- defp run_request(method, uri, body, headers, options), do: run_request(method, uri, body, headers, options, 0)
+ defp run_request(method, uri, body, headers, options),
+ do: run_request(method, uri, body, headers, options, 0)
+
defp run_request(method, uri, body, headers, options, retries) when retries < 4 do
case HTTPoison.request(method, uri, body, headers, options) do
{:error, :closed} -> run_request(method, uri, body, headers, options, retries + 1)
other -> other
end
end
- defp run_request(method, uri, body, headers, options, _exceeded_retries), do: {:error, :unavailable}
+
+ defp run_request(method, uri, body, headers, options, _exceeded_retries),
+ do: {:error, :unavailable}
#
# -- URIs
@@ -113,5 +130,4 @@ defmodule Nola.Icecast do
defp base_url do
"http://91.121.59.45:8089"
end
-
end
diff --git a/lib/nola/icecast_agent.ex b/lib/nola/icecast_agent.ex
index 8a3a72b..563b372 100644
--- a/lib/nola/icecast_agent.ex
+++ b/lib/nola/icecast_agent.ex
@@ -6,12 +6,10 @@ defmodule Nola.IcecastAgent do
end
def update(stats) do
- Agent.update(__MODULE__, fn(_old) -> stats end)
+ Agent.update(__MODULE__, fn _old -> stats end)
end
def get do
- Agent.get(__MODULE__, fn(stats) -> stats end)
+ Agent.get(__MODULE__, fn stats -> stats end)
end
-
end
-
diff --git a/lib/nola/membership.ex b/lib/nola/membership.ex
index 1c7303b..182f44d 100644
--- a/lib/nola/membership.ex
+++ b/lib/nola/membership.ex
@@ -7,11 +7,11 @@ defmodule Nola.Membership do
# Format: {key, last_seen}
defp dets() do
- to_charlist(Nola.data_path <> "/memberships.dets")
+ to_charlist(Nola.data_path() <> "/memberships.dets")
end
def start_link() do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_) do
@@ -25,9 +25,10 @@ defmodule Nola.Membership do
end
def merge_account(old_id, new_id) do
- #iex(37)> :ets.fun2ms(fn({{old_id, _, _}, _}=obj) when old_id == "42" -> obj end)
+ # iex(37)> :ets.fun2ms(fn({{old_id, _, _}, _}=obj) when old_id == "42" -> obj end)
spec = [{{{:"$1", :_, :_}, :_}, [{:==, :"$1", {:const, old_id}}], [:"$_"]}]
- Util.ets_mutate_select_each(:dets, dets(), spec, fn(table, obj = {{_old, net, chan}, ts}) ->
+
+ Util.ets_mutate_select_each(:dets, dets(), spec, fn table, obj = {{_old, net, chan}, ts} ->
:dets.delete_object(table, obj)
:dets.insert(table, {{new_id, net, chan}, ts})
end)
@@ -36,6 +37,7 @@ defmodule Nola.Membership do
def touch(%Nola.Account{id: id}, network, channel) do
:dets.insert(dets(), {{id, network, channel}, NaiveDateTime.utc_now()})
end
+
def touch(account_id, network, channel) do
if account = Nola.Account.get(account_id) do
touch(account, network, channel)
@@ -43,21 +45,28 @@ defmodule Nola.Membership do
end
def notify_channels(account, minutes \\ 30, last_active \\ true) do
- not_before = NaiveDateTime.add(NaiveDateTime.utc_now(), (minutes*-60), :second)
+ not_before = NaiveDateTime.add(NaiveDateTime.utc_now(), minutes * -60, :second)
spec = [{{{:"$1", :_, :_}, :_}, [{:==, :"$1", {:const, account.id}}], [:"$_"]}]
- memberships = :dets.select(dets(), spec)
- |> Enum.sort_by(fn({_, ts}) -> ts end, {:desc, NaiveDateTime})
- active_memberships = Enum.filter(memberships, fn({_, ts}) -> NaiveDateTime.compare(ts, not_before) == :gt end)
+
+ memberships =
+ :dets.select(dets(), spec)
+ |> Enum.sort_by(fn {_, ts} -> ts end, {:desc, NaiveDateTime})
+
+ active_memberships =
+ Enum.filter(memberships, fn {_, ts} -> NaiveDateTime.compare(ts, not_before) == :gt end)
+
cond do
active_memberships == [] && last_active ->
case memberships do
- [{{_, net, chan}, _}|_] -> [{net, chan}]
+ [{{_, net, chan}, _} | _] -> [{net, chan}]
_ -> []
end
+
active_memberships == [] ->
[]
+
true ->
- Enum.map(active_memberships, fn({{_, net, chan}, _}) -> {net,chan} end)
+ Enum.map(active_memberships, fn {{_, net, chan}, _} -> {net, chan} end)
end
end
@@ -78,16 +87,18 @@ defmodule Nola.Membership do
end
def members(network, channel) do
- #iex(19)> :ets.fun2ms(fn({{id, net, chan}, ts}) when net == network and chan == channel and ts > min_seen -> id end)
- limit = 0 # NaiveDateTime.add(NaiveDateTime.utc_now, 30*((24*-60)*60), :second)
+ # iex(19)> :ets.fun2ms(fn({{id, net, chan}, ts}) when net == network and chan == channel and ts > min_seen -> id end)
+ # NaiveDateTime.add(NaiveDateTime.utc_now, 30*((24*-60)*60), :second)
+ limit = 0
+
spec = [
{{{:"$1", :"$2", :"$3"}, :"$4"},
[
- {:andalso,
- {:andalso, {:==, :"$2", {:const, network}}, {:==, :"$3", {:const, channel}}},
+ {:andalso, {:andalso, {:==, :"$2", {:const, network}}, {:==, :"$3", {:const, channel}}},
{:>, :"$4", {:const, limit}}}
], [:"$1"]}
]
+
:dets.select(dets(), spec)
end
@@ -122,8 +133,6 @@ defmodule Nola.Membership do
{account, user, nick}
end
end
- |> Enum.filter(fn(x) -> x end)
+ |> Enum.filter(fn x -> x end)
end
-
-
end
diff --git a/lib/nola/message.ex b/lib/nola/message.ex
index b4e76da..1819e77 100644
--- a/lib/nola/message.ex
+++ b/lib/nola/message.ex
@@ -9,15 +9,14 @@ defmodule Nola.Message do
defstruct [
:id,
:text,
- {:transport, :irc},
- :network,
- :account,
- :sender,
- :channel,
- :trigger,
- :replyfun,
- :at,
- {:meta, %{}}
- ]
-
+ {:transport, :irc},
+ :network,
+ :account,
+ :sender,
+ :channel,
+ :trigger,
+ :replyfun,
+ :at,
+ {:meta, %{}}
+ ]
end
diff --git a/lib/nola/plugins.ex b/lib/nola/plugins.ex
index ac94736..6bfcfec 100644
--- a/lib/nola/plugins.ex
+++ b/lib/nola/plugins.ex
@@ -31,7 +31,7 @@ defmodule Nola.Plugins do
Nola.Plugins.Untappd,
Nola.Plugins.UserMention,
Nola.Plugins.WolframAlpha,
- Nola.Plugins.YouTube,
+ Nola.Plugins.YouTube
]
defmodule Supervisor do
@@ -44,13 +44,23 @@ defmodule Nola.Plugins do
def start_child(module, opts \\ []) do
Logger.info("Starting #{module}")
- spec = %{id: {Nola.Plugins,module}, start: {Nola.Plugins, :start_link, [module, opts]}, name: module, restart: :transient}
+
+ spec = %{
+ id: {Nola.Plugins, module},
+ start: {Nola.Plugins, :start_link, [module, opts]},
+ name: module,
+ restart: :transient
+ }
+
case DynamicSupervisor.start_child(__MODULE__, spec) do
- {:ok, _} = res -> res
+ {:ok, _} = res ->
+ res
+
:ignore ->
Logger.warn("Ignored #{module}")
:ignore
- {:error,_} = res ->
+
+ {:error, _} = res ->
Logger.error("Could not start #{module}: #{inspect(res, pretty: true)}")
res
end
@@ -73,10 +83,14 @@ defmodule Nola.Plugins do
end
def enabled() do
- :dets.foldl(fn
- {name, true, _}, acc -> [name | acc]
- _, acc -> acc
- end, [], dets())
+ :dets.foldl(
+ fn
+ {name, true, _}, acc -> [name | acc]
+ _, acc -> acc
+ end,
+ [],
+ dets()
+ )
end
def start_all() do
@@ -107,10 +121,12 @@ defmodule Nola.Plugins do
@doc "Enables or disables a plugin"
def switch(name, value) when is_boolean(value) do
- last = case get(name) do
- {:ok, last} -> last
- _ -> nil
- end
+ last =
+ case get(name) do
+ {:ok, last} -> last
+ _ -> nil
+ end
+
:dets.insert(dets(), {name, value, last})
end
@@ -124,8 +140,7 @@ defmodule Nola.Plugins do
def start_link(module, options \\ []) do
with {:disabled, {_, true, last}} <- {:disabled, get(module)},
- {:throttled, false} <- {:throttled, false}
- do
+ {:throttled, false} <- {:throttled, false} do
module.start_link()
else
{error, _} ->
@@ -133,5 +148,4 @@ defmodule Nola.Plugins do
:ignore
end
end
-
end
diff --git a/lib/nola/subnet.ex b/lib/nola/subnet.ex
index ac9d8e6..de469a6 100644
--- a/lib/nola/subnet.ex
+++ b/lib/nola/subnet.ex
@@ -17,22 +17,24 @@ defmodule Nola.Subnet do
end
def assign(binary) when is_binary(binary) do
- result = if subnet = find_subnet_for(binary) do
- {:ok, subnet}
- else
- Agent.get_and_update(__MODULE__, fn(dets) ->
- {subnet, _} = available_select(dets)
- :dets.insert(dets, {subnet, binary})
- :dets.sync(dets)
- {{:new, subnet}, dets}
- end)
- end
+ result =
+ if subnet = find_subnet_for(binary) do
+ {:ok, subnet}
+ else
+ Agent.get_and_update(__MODULE__, fn dets ->
+ {subnet, _} = available_select(dets)
+ :dets.insert(dets, {subnet, binary})
+ :dets.sync(dets)
+ {{:new, subnet}, dets}
+ end)
+ end
case result do
{:new, subnet} ->
ip = Pfx.host(subnet, 1)
set_reverse(binary, ip)
subnet
+
{:ok, subnet} ->
subnet
end
@@ -49,16 +51,40 @@ defmodule Nola.Subnet do
ip_fqdn = Pfx.dns_ptr(ip)
ip_local = String.replace(ip_fqdn, ".#{ptr_zone}", "")
rev? = String.ends_with?(value, ".users.goulag.org")
+
if rev? do
{:ok, rev_zone} = PowerDNSex.show_zone("users.goulag.org")
- rev_update? = Enum.any?(rev_zone.rrsets, fn(rr) -> rr.name == "#{ip_fqdn}." end)
- record = %{name: "#{value}.", type: "AAAA", ttl: 8600, records: [%{content: ip, disabled: false}]}
- if(rev_update?, do: PowerDNSex.update_record(rev_zone, record), else: PowerDNSex.create_record(rev_zone, record))
+ rev_update? = Enum.any?(rev_zone.rrsets, fn rr -> rr.name == "#{ip_fqdn}." end)
+
+ record = %{
+ name: "#{value}.",
+ type: "AAAA",
+ ttl: 8600,
+ records: [%{content: ip, disabled: false}]
+ }
+
+ if(rev_update?,
+ do: PowerDNSex.update_record(rev_zone, record),
+ else: PowerDNSex.create_record(rev_zone, record)
+ )
end
+
{:ok, zone} = PowerDNSex.show_zone(ptr_zone)
- update? = Enum.any?(zone.rrsets, fn(rr) -> rr.name == "#{ip_fqdn}." end)
- record = %{name: "#{ip_fqdn}.", type: "PTR", ttl: 3600, records: [%{content: "#{value}.", disabled: false}]}
- pdns = if(update?, do: PowerDNSex.update_record(zone, record), else: PowerDNSex.create_record(zone, record))
+ update? = Enum.any?(zone.rrsets, fn rr -> rr.name == "#{ip_fqdn}." end)
+
+ record = %{
+ name: "#{ip_fqdn}.",
+ type: "PTR",
+ ttl: 3600,
+ records: [%{content: "#{value}.", disabled: false}]
+ }
+
+ pdns =
+ if(update?,
+ do: PowerDNSex.update_record(zone, record),
+ else: PowerDNSex.create_record(zone, record)
+ )
+
:ok
end
@@ -76,9 +102,10 @@ defmodule Nola.Subnet do
defp available_select(dets) do
spec = [{{:"$1", :"$2"}, [is_integer: :"$2"], [{{:"$1", :"$2"}}]}]
{subnets, _} = :dets.select(dets, spec, 20)
- subnet = subnets
- |> Enum.sort_by(fn({_, last}) -> last end)
- |> List.first()
- end
+ subnet =
+ subnets
+ |> Enum.sort_by(fn {_, last} -> last end)
+ |> List.first()
+ end
end
diff --git a/lib/nola/token.ex b/lib/nola/token.ex
index 179bed2..f4fdd86 100644
--- a/lib/nola/token.ex
+++ b/lib/nola/token.ex
@@ -2,15 +2,15 @@ defmodule Nola.Token do
use GenServer
def start_link() do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def lookup(id) do
- with \
- [{_, cred, date}] <- :ets.lookup(__MODULE__.ETS, id),
- IO.inspect("cred: #{inspect cred} valid for #{inspect date} now #{inspect DateTime.utc_now()}"),
- d when d > 0 <- DateTime.diff(date, DateTime.utc_now())
- do
+ with [{_, cred, date}] <- :ets.lookup(__MODULE__.ETS, id),
+ IO.inspect(
+ "cred: #{inspect(cred)} valid for #{inspect(date)} now #{inspect(DateTime.utc_now())}"
+ ),
+ d when d > 0 <- DateTime.diff(date, DateTime.utc_now()) do
{:ok, cred}
else
err -> {:error, err}
@@ -22,17 +22,21 @@ defmodule Nola.Token do
end
def init(_) do
- ets = :ets.new(__MODULE__.ETS, [:ordered_set, :named_table, :protected, {:read_concurrency, true}])
+ ets =
+ :ets.new(__MODULE__.ETS, [:ordered_set, :named_table, :protected, {:read_concurrency, true}])
+
{:ok, ets}
end
def handle_call({:new, cred}, _, ets) do
id = Nola.UserTrack.Id.large_id()
- expire = DateTime.utc_now()
- |> DateTime.add(15*60, :second)
+
+ expire =
+ DateTime.utc_now()
+ |> DateTime.add(15 * 60, :second)
+
obj = {id, cred, expire}
:ets.insert(ets, obj)
{:reply, {:ok, id}, ets}
end
-
end
diff --git a/lib/nola/trigger.ex b/lib/nola/trigger.ex
index 1dec9ac..d3e791b 100644
--- a/lib/nola/trigger.ex
+++ b/lib/nola/trigger.ex
@@ -8,5 +8,4 @@ defmodule Nola.Trigger do
:trigger,
:args
]
-
end
diff --git a/lib/nola/user_track.ex b/lib/nola/user_track.ex
index c1218b0..0b07a91 100644
--- a/lib/nola/user_track.ex
+++ b/lib/nola/user_track.ex
@@ -8,23 +8,23 @@ defmodule Nola.UserTrack do
# Privilege map:
# %{"#channel" => [:operator, :voice]
defmodule Storage do
-
def delete(id) do
- op(fn(ets) -> :ets.delete(ets, id) end)
+ op(fn ets -> :ets.delete(ets, id) end)
end
def insert(tuple) do
- op(fn(ets) -> :ets.insert(ets, tuple) end)
+ op(fn ets -> :ets.insert(ets, tuple) end)
end
def clear_network(network) do
- op(fn(ets) ->
+ op(fn ets ->
spec = [
{{:_, :"$1", :_, :_, :_, :_, :_, :_, :_, :_, :_, :_},
- [
- {:==, :"$1", {:const, network}}
- ], [:"$_"]}
+ [
+ {:==, :"$1", {:const, network}}
+ ], [:"$_"]}
]
+
:ets.match_delete(ets, spec)
end)
end
@@ -34,7 +34,7 @@ defmodule Nola.UserTrack do
end
def start_link do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
@@ -43,13 +43,15 @@ defmodule Nola.UserTrack do
end
def handle_call({:op, fun}, _from, ets) do
- returned = try do
- {:ok, fun.(ets)}
- rescue
- rescued -> {:error, rescued}
- catch
- rescued -> {:error, rescued}
- end
+ returned =
+ try do
+ {:ok, fun.(ets)}
+ rescue
+ rescued -> {:error, rescued}
+ catch
+ rescued -> {:error, rescued}
+ end
+
{:reply, returned, ets}
end
@@ -58,31 +60,63 @@ defmodule Nola.UserTrack do
end
end
- defmodule Id, do: use EntropyString
+ defmodule Id, do: use(EntropyString)
defmodule User do
- defstruct [:id, :account, :network, :nick, {:nicks, []}, :username, :host, :realname, {:privileges, %{}}, {:last_active, %{}}, {:options, %{}}]
+ defstruct [
+ :id,
+ :account,
+ :network,
+ :nick,
+ {:nicks, []},
+ :username,
+ :host,
+ :realname,
+ {:privileges, %{}},
+ {:last_active, %{}},
+ {:options, %{}}
+ ]
def to_tuple(u = %__MODULE__{}) do
- {u.id || Nola.UserTrack.Id.large_id, u.network, u.account, String.downcase(u.nick), u.nick, u.nicks || [], u.username, u.host, u.realname, u.privileges, u.last_active, u.options}
+ {u.id || Nola.UserTrack.Id.large_id(), u.network, u.account, String.downcase(u.nick),
+ u.nick, u.nicks || [], u.username, u.host, u.realname, u.privileges, u.last_active,
+ u.options}
end
- #tuple size: 11
- def from_tuple({id, network, account, _downcased_nick, nick, nicks, username, host, realname, privs, last_active, opts}) do
- struct = %__MODULE__{id: id, account: account, network: network, nick: nick, nicks: nicks, username: username, host: host, realname: realname, privileges: privs, last_active: last_active, options: opts}
+ # tuple size: 11
+ def from_tuple(
+ {id, network, account, _downcased_nick, nick, nicks, username, host, realname, privs,
+ last_active, opts}
+ ) do
+ struct = %__MODULE__{
+ id: id,
+ account: account,
+ network: network,
+ nick: nick,
+ nicks: nicks,
+ username: username,
+ host: host,
+ realname: realname,
+ privileges: privs,
+ last_active: last_active,
+ options: opts
+ }
end
end
def find_by_account(%Nola.Account{id: id}) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
+ # iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
spec = [
{{:_, :_, :"$2", :_, :_, :_, :_, :_, :_, :_, :_, :_},
[
- {:==, :"$2", {:const, id}}
+ {:==, :"$2", {:const, id}}
], [:"$_"]}
]
- results = :ets.select(@ets, spec)
- |> Enum.filter(& &1)
+
+ results =
+ :ets.select(@ets, spec)
+ |> Enum.filter(& &1)
+
for obj <- results, do: User.from_tuple(obj)
end
@@ -91,27 +125,39 @@ defmodule Nola.UserTrack do
end
def find_by_account(network, %Nola.Account{id: id}) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
+ # iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
spec = [
{{:_, :"$1", :"$2", :_, :_, :_, :_, :_, :_, :_, :_, :_},
[
- {:andalso, {:==, :"$1", {:const, network}},
- {:==, :"$2", {:const, id}}}
+ {:andalso, {:==, :"$1", {:const, network}}, {:==, :"$2", {:const, id}}}
], [:"$_"]}
]
+
case :ets.select(@ets, spec) do
results = [_r | _] ->
- result = results
- |> Enum.reject(fn({_, net, _, _, _, _, _, _, _, _, actives, opts}) -> network != "matrix" && net == "matrix" end)
- |> Enum.reject(fn({_, net, _, _, _, _, _, _, _, _, actives, opts}) -> network != "telegram" && net == "telegram" end)
- |> Enum.reject(fn({_, _, _, _, _, _, _, _, _, _, actives, opts}) -> network not in ["matrix", "telegram"] && Map.get(opts, :puppet) end)
- |> Enum.sort_by(fn({_, _, _, _, _, _, _, _, _, _, actives, _}) ->
- Map.get(actives, nil)
- end, {:desc, NaiveDateTime})
- |> List.first
+ result =
+ results
+ |> Enum.reject(fn {_, net, _, _, _, _, _, _, _, _, actives, opts} ->
+ network != "matrix" && net == "matrix"
+ end)
+ |> Enum.reject(fn {_, net, _, _, _, _, _, _, _, _, actives, opts} ->
+ network != "telegram" && net == "telegram"
+ end)
+ |> Enum.reject(fn {_, _, _, _, _, _, _, _, _, _, actives, opts} ->
+ network not in ["matrix", "telegram"] && Map.get(opts, :puppet)
+ end)
+ |> Enum.sort_by(
+ fn {_, _, _, _, _, _, _, _, _, _, actives, _} ->
+ Map.get(actives, nil)
+ end,
+ {:desc, NaiveDateTime}
+ )
+ |> List.first()
if result, do: User.from_tuple(result)
- _ -> nil
+
+ _ ->
+ nil
end
end
@@ -119,18 +165,23 @@ defmodule Nola.UserTrack do
Storage.clear_network(network)
end
-
def merge_account(old_id, new_id) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
+ # iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
spec = [
{{:_, :_, :"$1", :_, :_, :_, :_, :_, :_, :_, :_, :_},
[
- {:==, :"$1", {:const, old_id}}
+ {:==, :"$1", {:const, old_id}}
], [:"$_"]}
]
- Enum.each(:ets.select(@ets, spec), fn({id, net, _, downcased_nick, nick, nicks, username, host, realname, privs, active, opts}) ->
- Storage.op(fn(ets) ->
- :ets.insert(@ets, {id, net, new_id, downcased_nick, nick, nicks, username, host, realname, privs, active, opts})
+
+ Enum.each(:ets.select(@ets, spec), fn {id, net, _, downcased_nick, nick, nicks, username,
+ host, realname, privs, active, opts} ->
+ Storage.op(fn ets ->
+ :ets.insert(
+ @ets,
+ {id, net, new_id, downcased_nick, nick, nicks, username, host, realname, privs, active,
+ opts}
+ )
end)
end)
end
@@ -139,14 +190,18 @@ defmodule Nola.UserTrack do
find_by_nick(network, nick)
end
-
def find_by_nick(%ExIRC.SenderInfo{network: network, nick: nick}) do
find_by_nick(network, nick)
end
def find_by_nick(network, nick) do
- case :ets.match(@ets, {:"$1", network, :_, String.downcase(nick), :_, :_, :_, :_, :_, :_, :_, :_}) do
- [[id] | _] -> lookup(id)
+ case :ets.match(
+ @ets,
+ {:"$1", network, :_, String.downcase(nick), :_, :_, :_, :_, :_, :_, :_, :_}
+ ) do
+ [[id] | _] ->
+ lookup(id)
+
_ ->
nil
end
@@ -171,7 +226,7 @@ defmodule Nola.UserTrack do
end
def channel(network, channel) do
- Enum.filter(to_list(), fn({_, network, _, _, _, _, _, _, _, channels, _, _}) ->
+ Enum.filter(to_list(), fn {_, network, _, _, _, _, _, _, _, channels, _, _} ->
Map.get(channels, channel)
end)
end
@@ -179,53 +234,92 @@ defmodule Nola.UserTrack do
# TODO
def connected(network, nick, user, host, account_id, opts \\ %{}) do
if account = Nola.Account.get(account_id) do
- user = if user = find_by_nick(network, nick) do
- user
- else
- user = %User{id: Nola.UserTrack.Id.large_id, account: account_id, network: network, nick: nick, username: user, host: host, privileges: %{}, options: opts}
- Storage.op(fn(ets) ->
- :ets.insert(ets, User.to_tuple(user))
- end)
- user
- end
+ user =
+ if user = find_by_nick(network, nick) do
+ user
+ else
+ user = %User{
+ id: Nola.UserTrack.Id.large_id(),
+ account: account_id,
+ network: network,
+ nick: nick,
+ username: user,
+ host: host,
+ privileges: %{},
+ options: opts
+ }
+
+ Storage.op(fn ets ->
+ :ets.insert(ets, User.to_tuple(user))
+ end)
+
+ user
+ end
+
+ Nola.Irc.Connection.publish_event(network, %{
+ type: :connect,
+ user_id: user.id,
+ account_id: user.account
+ })
- Nola.Irc.Connection.publish_event(network, %{type: :connect, user_id: user.id, account_id: user.account})
:ok
else
:error
end
end
- def joined(c, s), do: joined(c,s,[])
+ def joined(c, s), do: joined(c, s, [])
- def joined(channel, sender=%{nick: nick, user: uname, host: host}, privileges, touch \\ true) do
- privileges = if Nola.Irc.admin?(sender) do
- privileges ++ [:admin]
- else privileges end
- user = if user = find_by_nick(sender.network, nick) do
- %User{user | username: uname, host: host, privileges: Map.put(user.privileges || %{}, channel, privileges)}
- else
- user = %User{id: Nola.UserTrack.Id.large_id, network: sender.network, nick: nick, username: uname, host: host, privileges: %{channel => privileges}}
+ def joined(channel, sender = %{nick: nick, user: uname, host: host}, privileges, touch \\ true) do
+ privileges =
+ if Nola.Irc.admin?(sender) do
+ privileges ++ [:admin]
+ else
+ privileges
+ end
+
+ user =
+ if user = find_by_nick(sender.network, nick) do
+ %User{
+ user
+ | username: uname,
+ host: host,
+ privileges: Map.put(user.privileges || %{}, channel, privileges)
+ }
+ else
+ user = %User{
+ id: Nola.UserTrack.Id.large_id(),
+ network: sender.network,
+ nick: nick,
+ username: uname,
+ host: host,
+ privileges: %{channel => privileges}
+ }
+
+ account = Nola.Account.lookup(user).id
+ user = %User{user | account: account}
+ end
- account = Nola.Account.lookup(user).id
- user = %User{user | account: account}
- end
user = touch_struct(user, channel)
if touch && user.account do
Nola.Membership.touch(user.account, sender.network, channel)
end
- Storage.op(fn(ets) ->
+ Storage.op(fn ets ->
:ets.insert(ets, User.to_tuple(user))
end)
- Nola.Irc.Connection.publish_event({sender.network, channel}, %{type: :join, user_id: user.id, account_id: user.account})
+ Nola.Irc.Connection.publish_event({sender.network, channel}, %{
+ type: :join,
+ user_id: user.id,
+ account_id: user.account
+ })
user
end
- #def joined(network, channel, nick, privileges) do
+ # def joined(network, channel, nick, privileges) do
# user = if user = find_by_nick(network, nick) do
# %User{user | privileges: Map.put(user.privileges, channel, privileges)}
# else
@@ -235,18 +329,24 @@ defmodule Nola.UserTrack do
# Storage.op(fn(ets) ->
# :ets.insert(ets, User.to_tuple(user))
# end)
- #end
+ # end
+
+ def messaged(
+ %Nola.Message{network: network, account: account, channel: chan, sender: %{nick: nick}} =
+ m
+ ) do
+ {user, account} =
+ if user = find_by_nick(network, nick) do
+ {touch_struct(user, chan), account || Nola.Account.lookup(user)}
+ else
+ user = %User{network: network, nick: nick, privileges: %{}}
+ account = Nola.Account.lookup(user)
+ {%User{user | account: account.id}, account}
+ end
- def messaged(%Nola.Message{network: network, account: account, channel: chan, sender: %{nick: nick}} = m) do
- {user, account} = if user = find_by_nick(network, nick) do
- {touch_struct(user, chan), account || Nola.Account.lookup(user)}
- else
- user = %User{network: network, nick: nick, privileges: %{}}
- account = Nola.Account.lookup(user)
- {%User{user | account: account.id}, account}
- end
Storage.insert(User.to_tuple(user))
if chan, do: Nola.Membership.touch(account, network, chan)
+
if !m.account do
{:ok, %Nola.Message{m | account: account}}
else
@@ -257,12 +357,19 @@ defmodule Nola.UserTrack do
def renamed(network, old_nick, new_nick) do
if user = find_by_nick(network, old_nick) do
old_account = Nola.Account.lookup(user)
- user = %User{user | nick: new_nick, nicks: [old_nick|user.nicks]}
+ user = %User{user | nick: new_nick, nicks: [old_nick | user.nicks]}
account = Nola.Account.lookup(user, false) || old_account
- user = %User{user | nick: new_nick, account: account.id, nicks: [old_nick|user.nicks]}
+ user = %User{user | nick: new_nick, account: account.id, nicks: [old_nick | user.nicks]}
Storage.insert(User.to_tuple(user))
channels = for {channel, _} <- user.privileges, do: channel
- Nola.Irc.Connection.publish_event(network, %{type: :nick, user_id: user.id, account_id: account.id, nick: new_nick, old_nick: old_nick})
+
+ Nola.Irc.Connection.publish_event(network, %{
+ type: :nick,
+ user_id: user.id,
+ account_id: account.id,
+ nick: new_nick,
+ old_nick: old_nick
+ })
end
end
@@ -270,12 +377,19 @@ defmodule Nola.UserTrack do
if user = find_by_nick(network, nick) do
privs = Map.get(user.privileges, channel)
- privs = Enum.reduce(add, privs, fn(priv, acc) -> [priv|acc] end)
- privs = Enum.reduce(remove, privs, fn(priv, acc) -> List.delete(acc, priv) end)
+ privs = Enum.reduce(add, privs, fn priv, acc -> [priv | acc] end)
+ privs = Enum.reduce(remove, privs, fn priv, acc -> List.delete(acc, priv) end)
user = %User{user | privileges: Map.put(user.privileges, channel, privs)}
Storage.insert(User.to_tuple(user))
- Nola.Irc.Connection.publish_event({network, channel}, %{type: :privileges, user_id: user.id, account_id: user.account, added: add, removed: remove})
+
+ Nola.Irc.Connection.publish_event({network, channel}, %{
+ type: :privileges,
+ user_id: user.id,
+ account_id: user.account,
+ added: add,
+ removed: remove
+ })
end
end
@@ -292,12 +406,25 @@ defmodule Nola.UserTrack do
privs = Map.delete(user.privileges, channel)
lasts = Map.delete(user.last_active, channel)
+
if Enum.count(privs) > 0 do
user = %User{user | privileges: privs}
Storage.insert(User.to_tuple(user))
- Nola.Irc.Connection.publish_event({network, channel}, %{type: :part, user_id: user.id, account_id: user.account, reason: nil})
+
+ Nola.Irc.Connection.publish_event({network, channel}, %{
+ type: :part,
+ user_id: user.id,
+ account_id: user.account,
+ reason: nil
+ })
else
- Nola.Irc.Connection.publish_event(network, %{type: :quit, user_id: user.id, account_id: user.account, reason: "Left all known channels"})
+ Nola.Irc.Connection.publish_event(network, %{
+ type: :quit,
+ user_id: user.id,
+ account_id: user.account,
+ reason: "Left all known channels"
+ })
+
Storage.delete(user.id)
end
end
@@ -309,17 +436,27 @@ defmodule Nola.UserTrack do
for {channel, _} <- user.privileges do
Nola.Membership.touch(user.account, sender.network, channel)
end
- Nola.Irc.Connection.publish_event(sender.network, %{type: :quit, user_id: user.id, account_id: user.account, reason: reason})
+
+ Nola.Irc.Connection.publish_event(sender.network, %{
+ type: :quit,
+ user_id: user.id,
+ account_id: user.account,
+ reason: reason
+ })
end
+
Storage.delete(user.id)
end
end
defp touch_struct(user = %User{last_active: last_active}, channel) do
now = NaiveDateTime.utc_now()
- last_active = last_active
- |> Map.put(channel, now)
- |> Map.put(nil, now)
+
+ last_active =
+ last_active
+ |> Map.put(channel, now)
+ |> Map.put(nil, now)
+
%User{user | last_active: last_active}
end