defmodule OhMyExOhIrcd.IRC.Stats do
@moduledoc """
Cluster-wide counters for the landing page / dashboards.
Reads directly from the Horde registry + supervisor, so values reflect
the merged view across every node currently in the cluster.
"""
alias OhMyExOhIrcd.Cluster.{HordeRegistry, HordeSupervisor}
@spec channel_count() :: non_neg_integer()
def channel_count, do: length(channel_names())
@spec channel_names() :: [String.t()]
def channel_names do
Horde.Registry.select(HordeRegistry, [
{{{:channel, :"$1"}, :_, :_}, [], [:"$1"]}
])
end
@spec user_count() :: non_neg_integer()
def user_count, do: length(user_nicks())
@spec user_nicks() :: [String.t()]
def user_nicks do
Horde.Registry.select(HordeRegistry, [
{{{:user, :"$1"}, :_, :_}, [], [:"$1"]}
])
end
@doc """
Snapshot of every user currently connected anywhere in the cluster.
Queries each registered user pid (cross-node) for its WHOIS info, so a
slow / dead pid is skipped rather than blocking the whole list. Each
entry is tagged `:registered` (authenticated to an account),
`:anonymous` (connected without auth), or `:service` (ChanServ et al).
"""
@spec users() :: [map()]
def users do
service_nicks =
MapSet.new([
String.downcase(OhMyExOhIrcd.IRC.ChanServ.nick()),
String.downcase(OhMyExOhIrcd.IRC.ScrobbleServ.nick()),
String.downcase(OhMyExOhIrcd.IRC.ImgServ.nick())
])
Horde.Registry.select(HordeRegistry, [
{{{:user, :"$1"}, :"$2", :_}, [], [{{:"$1", :"$2"}}]}
])
|> Enum.map(fn {nick, pid} -> user_snapshot(nick, pid, service_nicks) end)
|> Enum.reject(&is_nil/1)
|> Enum.sort_by(&String.downcase(&1.nick))
end
defp user_snapshot(nick, pid, service_nicks) do
info = GenServer.call(pid, :whois_info, 1_000)
account = Map.get(info, :account)
kind =
cond do
MapSet.member?(service_nicks, String.downcase(nick)) -> :service
account -> :registered
true -> :anonymous
end
%{
nick: info.nick || nick,
user: Map.get(info, :user),
host: Map.get(info, :host),
real_host: Map.get(info, :real_host),
account: account,
away: Map.get(info, :away),
kind: kind,
node: node(pid)
}
catch
_, _ -> nil
end
@doc "Number of children of the Horde supervisor (all process types)."
def supervisor_child_count do
HordeSupervisor
|> Horde.DynamicSupervisor.which_children()
|> length()
end
@spec server_info() :: %{name: String.t(), network: String.t(), version: String.t()}
def server_info do
cfg = Application.get_env(:oh_my_ex_oh_ircd, OhMyExOhIrcd.IRC.Listener, [])
%{
name: Keyword.get(cfg, :server_name, "oh-my-ex-oh.irc"),
network: Keyword.get(cfg, :network_name, "OhMyExOhIRC"),
version: to_string(Application.spec(:oh_my_ex_oh_ircd, :vsn))
}
end
end
neiam
/oh-my-ex-oh-ircd
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
2.9 KiB · text
History
4b6fe3b