aboutsummaryrefslogtreecommitdiff
path: root/shard/lib/app/identity.ex
diff options
context:
space:
mode:
Diffstat (limited to 'shard/lib/app/identity.ex')
-rw-r--r--shard/lib/app/identity.ex113
1 files changed, 113 insertions, 0 deletions
diff --git a/shard/lib/app/identity.ex b/shard/lib/app/identity.ex
new file mode 100644
index 0000000..7e97897
--- /dev/null
+++ b/shard/lib/app/identity.ex
@@ -0,0 +1,113 @@
+defmodule SApp.Identity do
+ use GenServer
+
+ require Logger
+
+ defmodule Manifest do
+ defstruct [:pk]
+ end
+
+ defmodule State do
+ defstruct [:info, :rev, :signed]
+ end
+
+ defimpl Shard.Manifest, for: Manifest do
+ def start(m) do
+ DynamicSupervisor.start_child(Shard.DynamicSupervisor, {SApp.Identity, m.pk})
+ end
+ end
+
+ def start_link(pk) do
+ GenServer.start_link(__MODULE__, pk)
+ end
+
+ def init(pk) do
+ manifest = %Manifest{pk: pk}
+ id = SData.term_hash manifest
+
+ case Shard.Manager.register(id, manifest, self()) do
+ :ok ->
+ Shard.Manager.dispatch_to(id, nil, self())
+ state = case Shard.Manager.load_state(id) do
+ nil ->
+ info = %{nick: default_nick(pk)}
+ SData.SignRev.new info
+ st ->
+ st
+ end
+ GenServer.cast(self(), :init_pull)
+ {:ok, %{pk: pk, id: id, state: state}}
+ :redundant ->
+ exit(:redundant)
+ end
+ end
+
+ def default_nick(pk) do
+ nick_suffix = pk
+ |> binary_part(0, 4)
+ |> Base.encode16
+ |> String.downcase
+ "Anon" <> nick_suffix
+ end
+
+ def find_proc(pk) do
+ manifest = %Manifest{pk: pk}
+ id = SData.term_hash manifest
+ Shard.Manager.find_proc id
+ end
+
+ def handle_call(:manifest, _from, state) do
+ {:replyl, state.manifest, state}
+ end
+
+ def handle_call(:get_info, _from, state) do
+ {:reply, SData.SignRev.get(state.state), state}
+ 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, _, _} <- Shard.Manager.list_peers do
+ GenServer.cast(pid, {:send_msg, {:interested, [state.id]}})
+ end
+ {:noreply, state}
+ end
+
+ def handle_cast({:interested, peer_id}, state) do
+ Shard.Manager.send(peer_id, {state.id, nil, {:update, SData.SignRev.signed(state.state)}})
+ end
+
+ def handle_cast({:msg, peer_id, _shard_id, nil, msg}, state) do
+ state = case msg do
+ {:update, signed} ->
+ case SData.SignRev.merge(state.state, signed, state.pk) do
+ {true, st2} ->
+ Shard.Manager.save_state(state.id, st2)
+ state = put_in(state.state, st2)
+ bcast_state(state, [peer_id])
+ state
+ {false, _} ->
+ state
+ end
+ end
+ {: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
+ Shard.Manager.send(peer_id, {state.id, nil, {:update, SData.SignRev.signed(state.state)}})
+ end
+ end
+ end
+end