aboutsummaryrefslogtreecommitdiff
path: root/shard/lib/app
diff options
context:
space:
mode:
Diffstat (limited to 'shard/lib/app')
-rw-r--r--shard/lib/app/chat.ex57
-rw-r--r--shard/lib/app/identity.ex62
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