aboutsummaryrefslogtreecommitdiff
path: root/lib/app
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2018-07-04 13:17:26 +0200
committerAlex Auvolat <alex@adnab.me>2018-07-04 13:27:36 +0200
commitb234a360dafa0a65d797614aad5a4514570784f8 (patch)
treec636e7398fc8f3aba43b40c2fe67fc8264c56374 /lib/app
parentece5faa69da724ddfdee7b92016bac73dbdbff70 (diff)
downloadshard-b234a360dafa0a65d797614aad5a4514570784f8.tar.gz
shard-b234a360dafa0a65d797614aad5a4514570784f8.zip
Multiple chat rooms (no web UI yet)
Diffstat (limited to 'lib/app')
-rw-r--r--lib/app/chat.ex83
1 files changed, 76 insertions, 7 deletions
diff --git a/lib/app/chat.ex b/lib/app/chat.ex
index 4a56085..f165514 100644
--- a/lib/app/chat.ex
+++ b/lib/app/chat.ex
@@ -1,17 +1,86 @@
defmodule SApp.Chat do
- def send(msg) do
+ use GenServer
+
+ def start_link(channel) do
+ GenServer.start_link(__MODULE__, channel)
+ end
+
+ def init(channel) do
+ {:ok, store} = SData.MerkleList.start_link(&msg_cmp/2)
+ manifest = {:chat, channel}
+ id = :crypto.hash(:sha256, :erlang.term_to_binary(manifest))
+
+ GenServer.cast(Shard.Manager, {:register, id, self()})
+ GenServer.cast(self(), :init_pull)
+
+ {:ok, %{channel: channel, id: id, manifest: manifest, store: store, peers: %{}}}
+ end
+
+ def handle_call(:manifest, _from, state) do
+ {:reply, state.manifest, state}
+ end
+
+ def handle_cast({:redundant, _}, _state) do
+ exit :normal
+ end
+
+ def handle_cast(:init_pull, state) do
+ GenServer.call(SNet.Manager, :get_all)
+ |> Enum.each(&(GenServer.cast(&1, {:send_msg, {:interested, [state.id]}})))
+ {:noreply, state}
+ end
+
+ def handle_cast({:chat_send, msg}, state) do
msgitem = {(System.os_time :seconds),
Shard.Identity.get_nickname(),
msg}
- GenServer.cast(SApp.Chat.Log, {:insert, msgitem})
+ GenServer.cast(state.store, {:insert, msgitem})
+
+ for {_, pid} <- state.peers do
+ push_messages(state, pid, nil, 5)
+ end
- SNet.ConnSupervisor
- |> DynamicSupervisor.which_children
- |> Enum.each(fn {_, pid, _, _} -> GenServer.cast(pid, :init_push) end)
+ {:noreply, state}
end
- def msg_callback({ts, nick, msg}) do
- IO.puts "#{ts |> DateTime.from_unix! |> DateTime.to_iso8601} <#{nick}> #{msg}"
+ def handle_cast({:interested, peer_id, peer_pid}, state) do
+ push_messages(state, peer_pid, nil, 10)
+ new_peers = Map.put(state.peers, peer_id, peer_pid)
+ {:noreply, %{ state | peers: new_peers }}
+ end
+
+ def handle_cast({:msg, peer_id, peer_pid, msg}, state) do
+ case msg do
+ :get_top -> push_messages(peer_id, state, nil, 10)
+ {:get, start} -> push_messages(peer_id, state, start, 20)
+ {:info, _start, list, rest} ->
+ if rest != nil and not GenServer.call(state.store, {:has, rest}) do
+ GenServer.cast(peer_pid, {:send_msg, {state.id, {:get, rest}}})
+ end
+ spawn_link(fn ->
+ Process.sleep 1000
+ GenServer.cast(state.store, {:insert_many, list, (fn msg -> msg_callback(state.channel, msg) end)})
+ end)
+ end
+
+ if Map.has_key?(state.peers, peer_id) do
+ {:noreply, state}
+ else
+ handle_cast({:interested, peer_id, peer_pid}, state)
+ end
+ end
+
+ defp push_messages(state, to, start, num) do
+ case GenServer.call(state.store, {:read, start, num}) do
+ {:ok, list, rest} ->
+ GenServer.cast(to, {:send_msg, {state.id, {:info, start, list, rest}}})
+ _ -> nil
+ end
+ end
+
+
+ def msg_callback(chan, {ts, nick, msg}) do
+ IO.puts "#{ts |> DateTime.from_unix! |> DateTime.to_iso8601} ##{chan} <#{nick}> #{msg}"
end
def msg_cmp({ts1, nick1, msg1}, {ts2, nick2, msg2}) do