diff options
Diffstat (limited to 'lib/lsg_irc/txt_plugin.ex')
-rw-r--r-- | lib/lsg_irc/txt_plugin.ex | 141 |
1 files changed, 110 insertions, 31 deletions
diff --git a/lib/lsg_irc/txt_plugin.ex b/lib/lsg_irc/txt_plugin.ex index ca1be9c..f8c3a29 100644 --- a/lib/lsg_irc/txt_plugin.ex +++ b/lib/lsg_irc/txt_plugin.ex @@ -3,11 +3,11 @@ defmodule LSG.IRC.TxtPlugin do require Logger @moduledoc """ - # [txt](/irc/txt) + # [txt]({{context_path}}/txt) * **.txt**: liste des fichiers et statistiques. Les fichiers avec une `*` sont vérrouillés. - [Voir sur le web](/irc/txt). + [Voir sur le web]({{context_path}}/txt). * **!txt**: lis aléatoirement une ligne dans tous les fichiers. * **!txt `<recherche>`**: recherche une ligne dans tous les fichiers. @@ -56,7 +56,7 @@ defmodule LSG.IRC.TxtPlugin do # 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 + if channel && UserTrack.operator?(msg.network, channel, msg.sender.nick) do msg.replyfun.("txt: écriture réactivée") {:noreply, %__MODULE__{state | rw: true}} else @@ -65,7 +65,7 @@ defmodule LSG.IRC.TxtPlugin do end 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 + if channel && UserTrack.operator?(msg.network, channel, msg.sender.nick) do msg.replyfun.("txt: écriture désactivée") {:noreply, %__MODULE__{state | rw: false}} else @@ -80,7 +80,7 @@ defmodule LSG.IRC.TxtPlugin do def handle_info({:irc, :trigger, "txtlock", msg = %{trigger: %{type: :plus, args: [trigger]}}}, state) do with \ {trigger, _} <- clean_trigger(trigger), - true <- UserTrack.operator?(msg.channel, msg.sender.nick) + true <- UserTrack.operator?(msg.network, msg.channel, msg.sender.nick) do :dets.insert(state.locks, {trigger}) msg.replyfun.("txt: #{trigger} verrouillé") @@ -91,7 +91,7 @@ defmodule LSG.IRC.TxtPlugin do def handle_info({:irc, :trigger, "txtlock", msg = %{trigger: %{type: :minus, args: [trigger]}}}, state) do with \ {trigger, _} <- clean_trigger(trigger), - true <- UserTrack.operator?(msg.channel, msg.sender.nick), + true <- UserTrack.operator?(msg.network, msg.channel, msg.sender.nick), true <- :dets.member(state.locks, trigger) do :dets.delete(state.locks, trigger) @@ -132,7 +132,6 @@ defmodule LSG.IRC.TxtPlugin do def handle_info({:irc, :trigger, "txt", msg = %{trigger: %{type: :bang, args: []}}}, state) do result = Enum.reduce(state.triggers, [], fn({trigger, data}, acc) -> - IO.puts inspect(data) Enum.reduce(data, acc, fn({l, _}, acc) -> [{trigger, l} | acc] end) @@ -141,28 +140,92 @@ defmodule LSG.IRC.TxtPlugin do if !Enum.empty?(result) do {source, line} = Enum.random(result) - msg.replyfun.(format_line(line, "#{source}: ")) + msg.replyfun.(format_line(line, "#{source}: ", msg)) end {:noreply, state} end 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] + result = with_stateful_results(msg, {:bang,"txt",grep}, fn() -> + 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() 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) + if result do + {source, line} = result msg.replyfun.(["#{source}: ", line]) end {:noreply, state} end + def with_stateful_results(msg, key, initfun) do + me = self() + scope = {msg.network, msg.channel || msg.sender.nick} + key = {__MODULE__, me, scope, key} + with_stateful_results(key, initfun) + end + + def with_stateful_results(key, initfun) do + IO.puts("Stateful results key is #{inspect key}") + pid = case :global.whereis_name(key) do + :undefined -> + start_stateful_results(key, initfun.()) + pid -> pid + end + if pid, do: wait_stateful_results(key, initfun, pid) + end + + def start_stateful_results(key, []) do + nil + end + + def start_stateful_results(key, list) do + me = self() + {pid, _} = spawn_monitor(fn() -> + Process.monitor(me) + stateful_results(me, list) + end) + :yes = :global.register_name(key, pid) + pid + end + + def wait_stateful_results(key, initfun, pid) do + send(pid, :get) + receive do + {:stateful_results, line} -> + line + {:DOWN, _ref, :process, ^pid, reason} -> + with_stateful_results(key, initfun) + after + 5000 -> + nil + end + end + + defp stateful_results(owner, []) do + send(owner, :empty) + :ok + end + + @stateful_results_expire :timer.minutes(30) + defp stateful_results(owner, [line | rest] = acc) do + receive do + :get -> + send(owner, {:stateful_results, line}) + stateful_results(owner, rest) + {:DOWN, _ref, :process, ^owner, _} -> + :ok + after + @stateful_results_expire -> :ok + end + end + # # GLOBAL: MARKOV # @@ -209,12 +272,25 @@ defmodule LSG.IRC.TxtPlugin do # TXT: RANDOM # + def handle_info({:irc, :trigger, trigger, m = %{trigger: %{type: :query, args: opts}}}, state) do + {trigger, _} = clean_trigger(trigger) + if Map.get(state.triggers, trigger) do + url = if m.channel do + LSGWeb.Router.Helpers.irc_url(LSGWeb.Endpoint, :txt, m.network, LSGWeb.format_chan(m.channel), trigger) + else + LSGWeb.Router.Helpers.irc_url(LSGWeb.Endpoint, :txt, trigger) + end + m.replyfun.("-> #{url}") + end + {:noreply, state} + end + def handle_info({:irc, :trigger, trigger, msg = %{trigger: %{type: :bang, args: opts}}}, state) do {trigger, _} = clean_trigger(trigger) IO.puts "OPTS : #{inspect {trigger, opts}}" - line = get_random(state.triggers, trigger, String.trim(Enum.join(opts, " "))) + line = get_random(msg, state.triggers, trigger, String.trim(Enum.join(opts, " "))) if line do - msg.replyfun.(format_line(line)) + msg.replyfun.(format_line(line, nil, msg)) end {:noreply, state} end @@ -310,7 +386,7 @@ defmodule LSG.IRC.TxtPlugin do File.write!(directory() <> "/" <> trigger <> ".txt", data<>"\n", []) end - defp get_random(triggers, trigger, []) do + defp get_random(msg, triggers, trigger, []) do if data = Map.get(triggers, trigger) do {data, _idx} = Enum.random(data) data @@ -319,16 +395,16 @@ defmodule LSG.IRC.TxtPlugin do end end - defp get_random(triggers, trigger, opt) do + defp get_random(msg, triggers, trigger, opt) do arg = case Integer.parse(opt) do {pos, ""} -> {:index, pos} {_pos, _some_string} -> {:grep, opt} _error -> {:grep, opt} end - get_with_param(triggers, trigger, arg) + get_with_param(msg, triggers, trigger, arg) end - defp get_with_param(triggers, trigger, {:index, pos}) do + defp get_with_param(msg, triggers, trigger, {:index, pos}) do data = Map.get(triggers, trigger, %{}) case Enum.find(data, fn({_, index}) -> index+1 == pos end) do {text, _} -> text @@ -336,14 +412,15 @@ defmodule LSG.IRC.TxtPlugin do end end - defp get_with_param(triggers, trigger, {:grep, query}) do - data = Map.get(triggers, trigger, %{}) - regex = Regex.compile!("#{query}", "i") - out = Enum.filter(data, fn({txt, _}) -> Regex.match?(regex, txt) end) - |> Enum.map(fn({txt, _}) -> txt end) - if !Enum.empty?(out) do - Enum.random(out) - end + defp get_with_param(msg, triggers, trigger, {:grep, query}) do + out = with_stateful_results(msg, {:grep, trigger, query}, fn() -> + data = Map.get(triggers, trigger, %{}) + regex = Regex.compile!("#{query}", "i") + Enum.filter(data, fn({txt, _}) -> Regex.match?(regex, txt) end) + |> Enum.map(fn({txt, _}) -> txt end) + |> Enum.shuffle() + end) + if out, do: out end defp create_file(name) do @@ -380,7 +457,8 @@ defmodule LSG.IRC.TxtPlugin do {trigger, opts} end - defp format_line(line, prefix \\ "") do + defp format_line(line, prefix, msg) do + prefix = unless(prefix, do: "", else: prefix) prefix <> line |> String.split("\\\\") |> Enum.map(fn(line) -> @@ -389,6 +467,7 @@ defmodule LSG.IRC.TxtPlugin do |> List.flatten() |> Enum.map(fn(line) -> String.trim(line) + |> Tmpl.render(msg) end) end @@ -415,7 +494,7 @@ defmodule LSG.IRC.TxtPlugin do 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) + operator? = IRC.UserTrack.operator?(msg.network, channel, sender.nick) locked? = case :dets.lookup(locks, trigger) do [{trigger}] -> true _ -> false |