summaryrefslogtreecommitdiff
path: root/lib/lsg_irc/txt_plugin.ex
diff options
context:
space:
mode:
authorhref <href@random.sh>2020-03-11 21:18:34 +0100
committerhref <href@random.sh>2020-03-11 21:18:34 +0100
commita28d24470ddeca6196219a1333c1ccac1319efef (patch)
tree4f29e3c8fb6afbb1f99d6b8737f844c95fca54df /lib/lsg_irc/txt_plugin.ex
parentup to 420*100 (diff)
welp
Diffstat (limited to '')
-rw-r--r--lib/lsg_irc/txt_plugin.ex (renamed from lib/lsg_irc/txt_handler.ex)238
1 files changed, 152 insertions, 86 deletions
diff --git a/lib/lsg_irc/txt_handler.ex b/lib/lsg_irc/txt_plugin.ex
index 032c11c..6b7edbd 100644
--- a/lib/lsg_irc/txt_handler.ex
+++ b/lib/lsg_irc/txt_plugin.ex
@@ -1,101 +1,110 @@
-defmodule LSG.IRC.TxtHandler do
+defmodule LSG.IRC.TxtPlugin do
alias IRC.UserTrack
require Logger
@moduledoc """
# [txt](/irc/txt)
- * **!txt**: liste des fichiers et statistiques.
+ * **.txt**: liste des fichiers et statistiques.
Les fichiers avec une `*` sont vérrouillés.
[Voir sur le web](/irc/txt).
+ * **!txt**: lis aléatoirement une ligne dans tous les fichiers.
+ * **!txt `<recherche>`**: recherche une ligne dans tous les fichiers.
+
+ * **~txt**: essaie de générer une phrase (markov).
+ * **~txt `<début>`**: essaie de générer une phrase commencant par `<debut>`.
+
* **!`FICHIER`**: lis aléatoirement une ligne du fichier `FICHIER`.
* **!`FICHIER` `<chiffre>`**: lis la ligne `<chiffre>` du fichier `FICHIER`.
- * **!`FILE` `<recherche>`**: recherche une ligne contenant `<recherche>` dans `FICHIER`.
+ * **!`FICHIER` `<recherche>`**: recherche une ligne contenant `<recherche>` dans `FICHIER`.
* **+txt `<file`>**: crée le fichier `<file>`.
* **+`FICHIER` `<texte>`**: ajoute une ligne `<texte>` dans le fichier `FICHIER`.
* **-`FICHIER` `<chiffre>`**: supprime la ligne `<chiffre>` du fichier `FICHIER`.
- * **+txtro, +txtrw**. op seulement. active/désactive le mode lecture seule.
+ * **-txtrw, +txtrw**. op seulement. active/désactive le mode lecture seule.
* **+txtlock `<fichier>`, -txtlock `<fichier>`**. op seulement. active/désactive le verrouillage d'un fichier.
+
+ Insérez `\\\\` pour faire un saut de ligne.
"""
def short_irc_doc, do: "!txt https://sys.115ans.net/irc/txt "
def irc_doc, do: @moduledoc
- def start_link(client) do
- GenServer.start_link(__MODULE__, [client])
+ def start_link() do
+ GenServer.start_link(__MODULE__, [])
end
- defstruct client: nil, triggers: %{}, rw: true, locks: nil, markov: nil
+ defstruct triggers: %{}, rw: true, locks: nil, markov_handler: nil, markov: nil
- def init([client]) do
+ def init([]) do
dets_locks_filename = (LSG.data_path() <> "/" <> "txtlocks.dets") |> String.to_charlist
{:ok, locks} = :dets.open_file(dets_locks_filename, [])
- {:ok, markov} = ExChain.MarkovModel.start_link
- state = %__MODULE__{client: client, locks: locks, markov: markov}
- ExIRC.Client.add_handler(client, self())
- {:ok, %__MODULE__{state | triggers: load()}}
+ markov_handler = Keyword.get(Application.get_env(:lsg, __MODULE__, []), :markov_handler, LSG.IRC.TxtPlugin.Markov.Native)
+ {:ok, markov} = markov_handler.start_link()
+ {:ok, _} = Registry.register(IRC.PubSub, "triggers", [])
+ {:ok, %__MODULE__{locks: locks, markov_handler: markov_handler, markov: markov, triggers: load()}}
end
def handle_info({:received, "!reload", _, chan}, state) do
{:noreply, %__MODULE__{state | triggers: load()}}
end
- ## -- ADMIN RO/RW
- def handle_info({:received, "+txtrw", %ExIRC.SenderInfo{nick: nick}, chan}, state = %__MODULE__{rw: false}) do
- if UserTrack.operator?(chan, nick) do
- say(state, chan, "txt: écriture réactivée")
+ #
+ # ADMIN: RW/RO
+ #
+
+ def handle_info({:irc, :trigger, "txtrw", msg = %{channel: channel, trigger: %{type: :plus}}}, state = %{rw: false}) do
+ if channel && UserTrack.operator?(channel, msg.sender.nick) do
+ msg.replyfun.("txt: écriture réactivée")
{:noreply, %__MODULE__{state | rw: true}}
else
{:noreply, state}
end
end
- def handle_info({:received, "+txtro", %ExIRC.SenderInfo{nick: nick}, chan}, state = %__MODULE__{rw: true}) do
- if UserTrack.operator?(chan, nick) do
- say(state, chan, "txt: écriture désactivée")
+ def handle_info({:irc, :trigger, "txtrw", msg = %{channel: channel, trigger: %{type: :minus}}}, state = %{rw: true}) do
+ if channel && UserTrack.operator?(channel, msg.sender.nick) do
+ msg.replyfun.("txt: écriture désactivée")
{:noreply, %__MODULE__{state | rw: false}}
else
{:noreply, state}
end
end
- def handle_info({:received, "+txtro", _, _}, state) do
- {:noreply, state}
- end
- def handle_info({:received, "+txtrw", _, _}, state) do
- {:noreply, state}
- end
+ #
+ # ADMIN: LOCKS
+ #
- ## -- ADMIN LOCKS
- def handle_info({:received, "+txtlock " <> trigger, %ExIRC.SenderInfo{nick: nick}, chan}, state) do
+ def handle_info({:irc, :trigger, "txtlock", msg = %{trigger: %{type: :plus, args: [trigger]}}}, state) do
with \
{trigger, _} <- clean_trigger(trigger),
- true <- UserTrack.operator?(chan, nick)
+ true <- UserTrack.operator?(msg.channel, msg.sender.nick)
do
:dets.insert(state.locks, {trigger})
- say(state, chan, "txt: #{trigger} verrouillé")
+ msg.replyfun.("txt: #{trigger} verrouillé")
end
{:noreply, state}
end
- def handle_info({:received, "-txtlock " <> trigger, %ExIRC.SenderInfo{nick: nick}, chan}, state) do
+ def handle_info({:irc, :trigger, "txtlock", msg = %{trigger: %{type: :minus, args: [trigger]}}}, state) do
with \
{trigger, _} <- clean_trigger(trigger),
- true <- UserTrack.operator?(chan, nick),
+ true <- UserTrack.operator?(msg.channel, msg.sender.nick),
true <- :dets.member(state.locks, trigger)
do
:dets.delete(state.locks, trigger)
- say(state, chan, "txt: #{trigger} déverrouillé")
+ msg.replyfun.("txt: #{trigger} déverrouillé")
end
{:noreply, state}
end
- # -- ADD
+ #
+ # FILE LIST
+ #
- def handle_info({:received, "!txt", _, chan}, state) do
+ def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :dot}}}, state) do
map = Enum.map(state.triggers, fn({key, data}) ->
locked? = case :dets.lookup(state.locks, key) do
[{trigger}] -> "*"
@@ -113,103 +122,147 @@ defmodule LSG.IRC.TxtHandler do
ro = if !state.rw, do: " (lecture seule activée)", else: ""
(detail<>total<>ro)
- |> String.codepoints
- |> Enum.chunk_every(440)
- |> Enum.map(&Enum.join/1)
- |> Enum.map(fn(line) -> ExIRC.Client.msg(state.client, :privmsg, chan, line) end)
+ |> msg.replyfun.()
{:noreply, state}
end
- def handle_info({:received, "~txt", _, chan}, state) do
- case ExChain.SentenceGenerator.create_filtered_sentence(state.markov) do
- {:ok, line, _, _} ->
- ExIRC.Client.msg(state.client, :privmsg, chan, line)
- error ->
- Logger.error "Txt Markov error: "<>inspect error
+ #
+ # GLOBAL: RANDOM
+ #
+
+ def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :bang, args: []}}}, state) do
+ result = Enum.reduce(state.triggers, [], fn({trigger, data}, acc) ->
+ Enum.reduce(data, acc, fn({l, _}, acc) ->
+ [{trigger, l} | acc]
+ end)
+ end)
+ |> Enum.shuffle()
+
+ if !Enum.empty?(result) do
+ {source, line} = Enum.random(result)
+ msg.replyfun.("#{source}: #{line}")
end
{:noreply, state}
end
- def handle_info({:received, "~txt "<>complete, _, chan}, state) do
- case ExChain.SentenceGenerator.complete_sentence(state.markov, complete) do
- {line, _} ->
- ExIRC.Client.msg(state.client, :privmsg, chan, line)
+
+ def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :bang, args: args}}}, state) do
+ grep = Enum.join(args, " ")
+ result = Enum.reduce(state.triggers, [], fn({trigger, data}, acc) ->
+ Enum.reduce(data, acc, fn({l, _}, acc) ->
+ [{trigger, l} | acc]
+ end)
+ end)
+ |> Enum.filter(fn({_, line}) -> String.contains?(String.downcase(line), String.downcase(grep)) end)
+ |> Enum.shuffle()
+
+ if !Enum.empty?(result) do
+ {source, line} = Enum.random(result)
+ msg.replyfun.("#{source}: #{line}")
+ end
+ {:noreply, state}
+ end
+
+ #
+ # GLOBAL: MARKOV
+ #
+
+ def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :tilde, args: []}}}, state) do
+ case state.markov_handler.sentence(state.markov) do
+ {:ok, line} ->
+ msg.replyfun.(line)
error ->
Logger.error "Txt Markov error: "<>inspect error
end
{:noreply, state}
end
- def handle_info({:received, "!"<>trigger, _, chan}, state) do
- {trigger, opts} = clean_trigger(trigger)
- line = get_random(state.triggers, trigger, opts)
- if line do
- ExIRC.Client.msg(state.client, :privmsg, chan, line)
+ def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :tilde, args: complete}}}, state) do
+ complete = Enum.join(complete, " ")
+ case state.markov_handler.complete_sentence(complete, state.markov) do
+ {:ok, line} ->
+ msg.replyfun.(line)
+ error ->
+ Logger.error "Txt Markov error: "<>inspect error
end
{:noreply, state}
end
- def handle_info({:received, "+txt "<>trigger, sender=%ExIRC.SenderInfo{nick: nick}, chan}, state) do
+ #
+ # TXT CREATE
+ #
+
+ def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :plus, args: [trigger]}}}, state) do
with \
{trigger, _} <- clean_trigger(trigger),
- true <- can_write?(state, chan, sender, trigger),
+ true <- can_write?(state, msg, trigger),
:ok <- create_file(trigger)
do
- ExIRC.Client.msg(state.client, :privmsg, chan, "#{trigger}.txt créé. Ajouter: `+#{trigger} …` ; Lire: `!#{trigger}`")
+ msg.replyfun.("#{trigger}.txt créé. Ajouter: `+#{trigger} …` ; Lire: `!#{trigger}`")
{:noreply, %__MODULE__{state | triggers: load()}}
else
_ -> {:noreply, state}
end
end
- def handle_info({:received, "+"<>trigger_and_content, sender=%ExIRC.SenderInfo{nick: nick}, chan}, state) do
+ #
+ # TXT: RANDOM
+ #
+
+ def handle_info({:irc, :trigger, trigger, msg = %{trigger: %{type: :bang, args: []}}}, state) do
+ {trigger, opts} = clean_trigger(trigger)
+ line = get_random(state.triggers, trigger, opts)
+ if line do
+ msg.replyfun.(line)
+ end
+ {:noreply, state}
+ end
+
+ #
+ # TXT: ADD
+ #
+
+ def handle_info({:irc, :trigger, trigger, msg = %{trigger: %{type: :plus, args: content}}}, state) do
with \
- {trigger, _} <- clean_trigger(trigger_and_content),
- true <- can_write?(state, chan, sender, trigger),
- {:ok, idx} <- add(state.triggers, trigger_and_content)
+ true <- can_write?(state, msg, trigger),
+ {:ok, idx} <- add(state.triggers, msg.text)
do
- ExIRC.Client.msg(state.client, :privmsg, chan, "#{nick}: ajouté à #{trigger}. (#{idx})")
+ msg.replyfun.("#{msg.sender.nick}: ajouté à #{trigger}. (#{idx})")
{:noreply, %__MODULE__{state | triggers: load()}}
else
- _ -> {:noreply, state}
+ _ ->
+ {:noreply, state}
end
end
- def handle_info({:received, "-"<>trigger_and_id, sender=%ExIRC.SenderInfo{nick: nick}, chan}, state) do
+ #
+ # TXT: DELETE
+ #
+
+ def handle_info({:irc, :trigger, trigger, msg = %{trigger: %{type: :minus, args: [id]}}}, state) do
with \
- [trigger, id] <- String.split(trigger_and_id, " ", parts: 2),
- {trigger, _} = clean_trigger(trigger),
- true <- can_write?(state, chan, sender, trigger),
+ true <- can_write?(state, msg, trigger),
data <- Map.get(state.triggers, trigger),
{id, ""} <- Integer.parse(id),
{text, _id} <- Enum.find(data, fn({_, idx}) -> id-1 == idx end)
do
data = data |> Enum.into(Map.new)
data = Map.delete(data, text)
- ExIRC.Client.msg(state.client, :privmsg, chan, "#{trigger}.txt##{id} supprimée: #{text}")
+ msg.replyfun.("#{msg.sender.nick}: #{trigger}.txt##{id} supprimée: #{text}")
dump(trigger, data)
{:noreply, %__MODULE__{state | triggers: load()}}
else
- error ->
- IO.inspect("error " <> inspect(error))
+ _ ->
{:noreply, state}
end
end
def handle_info(:reload_markov, state=%__MODULE__{triggers: triggers, markov: markov}) do
- all_data = triggers
- |> Enum.map(fn({_, data}) ->
- for {line, _idx} <- data, do: line
- end)
- |> List.flatten
-
- for l <- all_data, do: IO.puts(l)
-
- populate = ExChain.MarkovModel.populate_model(markov, all_data)
- IO.puts "populated markov: #{inspect(populate)}"
+ state.markov_handler.reload(state.triggers, state.markov)
{:noreply, state}
end
def handle_info(msg, state) do
+ IO.puts "txt unhandled #{inspect msg}"
{:noreply, state}
end
@@ -334,29 +387,42 @@ defmodule LSG.IRC.TxtHandler do
{trigger, opts}
end
- defp directory() do
+ def directory() do
Application.get_env(:lsg, :data_path) <> "/irc.txt/"
end
- defp can_write?(state = %__MODULE__{rw: rw?, locks: locks}, channel, sender, trigger) do
+ defp can_write?(%{rw: rw?, locks: locks}, msg = %{channel: nil, sender: sender}, trigger) do
admin? = IRC.admin?(sender)
- operator? = IRC.UserTrack.operator?(channel, sender.nick)
locked? = case :dets.lookup(locks, trigger) do
[{trigger}] -> true
_ -> false
end
unlocked? = if rw? == false, do: false, else: !locked?
- can? = admin? || operator? || unlocked?
+
+ can? = unlocked? || admin?
if !can? do
reason = if !rw?, do: "lecture seule", else: "fichier vérrouillé"
- say(state, channel, "#{sender.nick}: permission refusée (#{reason})")
+ msg.replyfun.("#{sender.nick}: permission refusée (#{reason})")
end
can?
end
- defp say(%__MODULE__{client: client}, chan, message) do
- ExIRC.Client.msg(client, :privmsg, chan, message)
+ defp can_write?(state = %__MODULE__{rw: rw?, locks: locks}, msg = %{channel: channel, sender: sender}, trigger) do
+ admin? = IRC.admin?(sender)
+ operator? = IRC.UserTrack.operator?(channel, sender.nick)
+ locked? = case :dets.lookup(locks, trigger) do
+ [{trigger}] -> true
+ _ -> false
+ end
+ unlocked? = if rw? == false, do: false, else: !locked?
+ can? = admin? || operator? || unlocked?
+
+ if !can? do
+ reason = if !rw?, do: "lecture seule", else: "fichier vérrouillé"
+ msg.replyfun.("#{sender.nick}: permission refusée (#{reason})")
+ end
+ can?
end
end