diff options
Diffstat (limited to 'shard/lib/app')
-rw-r--r-- | shard/lib/app/chat.ex | 57 | ||||
-rw-r--r-- | shard/lib/app/identity.ex | 62 |
2 files changed, 82 insertions, 37 deletions
diff --git a/shard/lib/app/chat.ex b/shard/lib/app/chat.ex index 53767ef..61403b8 100644 --- a/shard/lib/app/chat.ex +++ b/shard/lib/app/chat.ex @@ -7,6 +7,10 @@ defmodule SApp.Chat do %SApp.Chat.Manifest{channel: channel_name} + A private chat room manifest is of the form: + + %SApp.Chat.PrivChat.Manifest{pk_list: ordered_list_of_authorized_pks} + Future improvements: - message signing - storage of the chatroom messages to disk @@ -22,6 +26,10 @@ defmodule SApp.Chat do alias SData.MerkleSearchTree, as: MST + # ========= + # MANIFESTS + # ========= + defmodule Manifest do defstruct [:channel] end @@ -33,6 +41,24 @@ defmodule SApp.Chat do end + defmodule PrivChat.Manifest do + defstruct [:pk_list] + + def new(pk_list) do + %__MODULE__{pk_list: Enum.sort(pk_list)} + end + end + + defimpl Shard.Manifest, for: PrivChat.Manifest do + def start(m) do + DynamicSupervisor.start_child(Shard.DynamicSupervisor, {SApp.Chat, m}) + end + end + + # ========== + # MAIN LOGIC + # ========== + @doc """ Start a process that connects to a given channel """ @@ -44,7 +70,6 @@ defmodule SApp.Chat do Initialize channel process. """ def init(manifest) do - %Manifest{channel: channel} = manifest id = SData.term_hash manifest case Shard.Manager.register(id, manifest, self()) do @@ -62,12 +87,16 @@ defmodule SApp.Chat do mst = %MST{store: %SApp.PageStore{pid: page_store}, cmp: &msg_cmp/2, root: root} - group = %SNet.PubShardGroup{id: id} - SNet.Group.init_lookup(group, self()) + netgroup = case manifest do + %Manifest{channel: _channel} -> + %SNet.PubShardGroup{id: id} + %PrivChat.Manifest{pk_list: pk_list} -> + %SNet.PrivGroup{pk_list: pk_list} + end + SNet.Group.init_lookup(netgroup, self()) {:ok, - %{channel: channel, - id: id, - group: group, + %{id: id, + netgroup: netgroup, manifest: manifest, page_store: page_store, mst: mst, @@ -114,13 +143,19 @@ defmodule SApp.Chat do for pid <- state.subs do if Process.alive?(pid) do - send(pid, {:chat_send, state.channel, msgitem}) + send(pid, {:chat_send, state.manifest, msgitem}) end end notif = {state.id, nil, {:append, prev_root, msgitem, mst.root}} - SNet.Group.broadcast(state.group, notif) + SNet.Group.broadcast(state.netgroup, notif) + + {:noreply, state} + end + def handle_cast({:peer_connected, conn_pid}, state) do + # this is called by the SNet.Group thing so it is already authenticated + SNet.Manager.send_pid(conn_pid, {state.id, nil, {:root, state.mst.root}}) {:noreply, state} end @@ -129,7 +164,7 @@ defmodule SApp.Chat do connected to asks to recieve data for this channel. """ def handle_cast({:interested, conn_pid, auth}, state) do - if SNet.Group.in_group?(state.group, conn_pid, auth) do + if SNet.Group.in_group?(state.netgroup, conn_pid, auth) do SNet.Manager.send_pid(conn_pid, {state.id, nil, {:root, state.mst.root}}) end {:noreply, state} @@ -151,7 +186,7 @@ defmodule SApp.Chat do Merkle hash of the store of older messages. """ def handle_cast({:msg, conn_pid, auth, _shard_id, nil, msg}, state) do - if not SNet.Group.in_group?(state.group, conn_pid, auth) do + if not SNet.Group.in_group?(state.netgroup, conn_pid, auth) do # Ignore message {:noreply, state} else @@ -250,7 +285,7 @@ defmodule SApp.Chat do defp msg_callback(state, {pk, msgbin, sign}) do for pid <- state.subs do if Process.alive?(pid) do - send(pid, {:chat_recv, state.channel, {pk, msgbin, sign}}) + send(pid, {:chat_recv, state.manifest, {pk, msgbin, sign}}) end end end diff --git a/shard/lib/app/identity.ex b/shard/lib/app/identity.ex index 391d37e..255bebb 100644 --- a/shard/lib/app/identity.ex +++ b/shard/lib/app/identity.ex @@ -35,8 +35,12 @@ defmodule SApp.Identity do st -> st end - GenServer.cast(self(), :init_pull) - {:ok, %{pk: pk, id: id, state: state}} + netgroup = %SNet.PubShardGroup{id: id} + SNet.Group.init_lookup(netgroup, self()) + if Shard.Keys.have_sk? pk do + GenServer.cast(self(), :update_peer_info) + end + {:ok, %{pk: pk, id: id, state: state, netgroup: netgroup}} :redundant -> exit(:redundant) end @@ -52,7 +56,8 @@ defmodule SApp.Identity do id = SData.term_hash manifest case Shard.Manager.find_proc id do nil -> - Shard.Manifest.start manifest + {:ok, pid} = Shard.Manifest.start manifest + pid pid -> pid end end @@ -64,7 +69,7 @@ defmodule SApp.Identity do end def handle_call(:manifest, _from, state) do - {:replyl, state.manifest, state} + {:reply, state.manifest, state} end def handle_call(:get_info, _from, state) do @@ -72,22 +77,15 @@ defmodule SApp.Identity do end def handle_call({:set_info, new_info}, _from, state) do - case SData.SignRev.set(state.state, new_info, state.pk) do - {:ok, st2} -> - Shard.Manager.save_state(state.id, st2) - state = put_in(state.state, st2) - bcast_state(state) - {:reply, :ok, state} - err -> - {:reply, err, state} - end - end - - def handle_cast(:init_pull, state) do - for {_, pid, _} <- SNet.Manager.list_connections do - GenServer.cast(pid, {:send_msg, {:interested, [state.id]}}) + if Shard.Keys.have_sk?(state.pk) do + {:ok, st2} = SData.SignRev.set(state.state, new_info, state.pk) + Shard.Manager.save_state(state.id, st2) + state = put_in(state.state, st2) + bcast_state(state) + {:reply, :ok, state} + else + {:reply, :impossible, state} end - {:noreply, state} end def handle_cast({:interested, peer_pid, _auth}, state) do @@ -102,7 +100,7 @@ defmodule SApp.Identity do {true, st2} -> Shard.Manager.save_state(state.id, st2) state = put_in(state.state, st2) - bcast_state(state, [GenServer.call(conn_pid, :get_peer_info)]) + bcast_state(state, [conn_pid]) state {false, _} -> state @@ -112,11 +110,23 @@ defmodule SApp.Identity do {:noreply, state} end - def bcast_state(state, exclude \\ []) do - for peer_id <- Shard.Manager.get_shard_peers(state.id) do - if not Enum.member? exclude, peer_id do - SNet.Manager.send(peer_id, {state.id, nil, {:update, SData.SignRev.signed(state.state)}}) - end - end + def handle_cast(:update_peer_info, state) do + peer_info = SNet.Addr.get_all_inet4() + |> Enum.map(&({:inet, &1, Application.get_env(:shard, :port)})) + + prev_info = SData.SignRev.get(state.state) + # TODO multi peer info + new_info = Map.put(prev_info, :peer_info, peer_info) + {:ok, st2} = SData.SignRev.set(state.state, new_info, state.pk) + + Shard.Manager.save_state(state.id, st2) + state = put_in(state.state, st2) + bcast_state(state) + {:noreply, state} + end + + def bcast_state(state, _exclude \\ []) do + # TODO: effectively apply exclude list + SNet.Group.broadcast(state.netgroup, {state.id, nil, {:update, SData.SignRev.signed(state.state)}}) end end |