diff options
author | href <href@random.sh> | 2020-03-11 21:18:34 +0100 |
---|---|---|
committer | href <href@random.sh> | 2020-03-11 21:18:34 +0100 |
commit | a28d24470ddeca6196219a1333c1ccac1319efef (patch) | |
tree | 4f29e3c8fb6afbb1f99d6b8737f844c95fca54df /lib/lsg_irc/txt_plugin.ex | |
parent | up 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 |