diff options
-rw-r--r-- | TODO | 86 | ||||
-rw-r--r-- | shard/lib/app/chat.ex | 6 | ||||
-rw-r--r-- | shard/lib/app/identity.ex | 56 | ||||
-rw-r--r-- | shard/lib/cli/cli.ex | 35 | ||||
-rw-r--r-- | shard/lib/manager.ex | 16 | ||||
-rw-r--r-- | shardweb/lib/shard_web/channels/room_channel.ex | 12 |
6 files changed, 103 insertions, 108 deletions
@@ -10,19 +10,26 @@ achieves our goals. TASK LIST ========= -- Highest priority: comm, privchat, ep +- High priority: invite - Medium priority: dht, dep -Architecture for communication primitives (comm, MED) ------------------------------------------ +Invitation system (invite, EASY) +-------------------------------- -Find the right abstraction(s) for communiation channels. +A user may generate invitation tokens: an invite token is a signature of the +invited user's pk by the inviter user's sk. The user that redeems the token +writes some data that is saved temporarily in the user's identity shard, which +might be stored by a 3rd party node for instance if we are on mobile devices +that cannot connect directly. + + +Networking improvements (net, HARD) +----------------------- Here are some things to keep in mind that we want at some point: -- Encrypted point to point communication (to communicate private info after ACL check) -- Flooding, gossip, RPS +- RPS - Congestion control, proper multiplexing of feeds - Proper management of open connections to peers @@ -43,22 +50,6 @@ Second option: custom DHT protocol (we probably won't be doing this anytime soon, if ever at all) -Epidemic broadcast (ep, EASY) ------------------- - -When a shard recieves new information from a peer, transfer that -information to some other neigbors. - -How to select such neighbors ? - -a. All those that we know of -b. Those that we are currently connected to -c. A random number of known peers - -Best option: those that we are connected to + some random to -reach a quota (for example 10 or so) - - Partial merges, background pulls, caching (cache, req: bg, HARD) ----------------------------------------- @@ -78,22 +69,6 @@ infrequently used pages, for examples those of old data that is only kept for archival purpose. -Private chat (privchat, MED) ------------- - -Proof-of-concept for private things: shard for private chat between two people. - - -Invitation system (invite, EASY) --------------------------------- - -A user may generate invitation tokens: an invite token is a (sk, pk) plus a -signature of pk by the user's sk. The user that redeems the token writes some -data signed by sk that is saved temporarily in the user's identity shard, which -might be stored by a 3rd party node for instance if we are on mobile devices -that cannot connect directly. - - User groups and access control (groups, req: sign, HARD) ------------------------------ @@ -124,8 +99,8 @@ access control decisions (obviously these can only run when an identity with admin privilege is running). -Shard dependency management (dep, MED) ---------------------------- +Shard lifetime and dependency management (dep, MED) +---------------------------------------- Some Shards may pull other shards in, under certain conditions. For example a stored folder shard will just be a list of other shards that we all pull in. @@ -181,3 +156,34 @@ a correct signature from a certain identity. We can have a special "identity" shard type that enables storing profile information such as nickname or other information that we might want to make public. + + +Architecture for communication primitives (comm, MED) +----------------------------------------- + +- Encrypted point to point communication (to communicate private info after ACL check) -> SHS +- Flooding, gossip -> netgroups + + +Private chat (privchat, MED) +------------ + +Proof-of-concept for private things: shard for private chat between two people. + + +Epidemic broadcast (ep, EASY) +------------------ + +When a shard recieves new information from a peer, transfer that +information to some other neigbors. + +How to select such neighbors ? + +a. All those that we know of +b. Those that we are currently connected to +c. A random number of known peers + +Best option: those that we are connected to + some random to +reach a quota (for example 10 or so) + +Implementation: netgroups (lib/net/groups.ex) diff --git a/shard/lib/app/chat.ex b/shard/lib/app/chat.ex index 35ecdbf..ea210d8 100644 --- a/shard/lib/app/chat.ex +++ b/shard/lib/app/chat.ex @@ -108,12 +108,6 @@ defmodule SApp.Chat do end end - def find_proc(chan) do - manifest = %Manifest{channel: chan} - id = SData.term_hash manifest - Shard.Manager.find_proc id - end - @doc """ Implementation of the :manifest call that returns the chat room's manifest """ diff --git a/shard/lib/app/identity.ex b/shard/lib/app/identity.ex index 06bc225..02e8eb9 100644 --- a/shard/lib/app/identity.ex +++ b/shard/lib/app/identity.ex @@ -46,30 +46,6 @@ defmodule SApp.Identity do end end - def default_nick(pk) do - nick_suffix = Shard.Keys.pk_display pk - "Anon" <> nick_suffix - end - - def find_proc(pk) do - manifest = %Manifest{pk: pk} - id = SData.term_hash manifest - case Shard.Manager.find_proc id do - nil -> - case Shard.Manifest.start manifest do - {:ok, pid} -> pid - {:error, :redundant} -> find_proc(pk) - end - pid -> pid - end - end - - def get_nick(pk) do - pid = find_proc pk - info = GenServer.call(pid, :get_info) - info.nick - end - def handle_call(:manifest, _from, state) do {:reply, state.manifest, state} end @@ -136,8 +112,38 @@ defmodule SApp.Identity do {:noreply, state} end - def bcast_state(state, _exclude \\ []) do + defp bcast_state(state, _exclude \\ []) do # TODO: effectively apply exclude list SNet.Group.broadcast(state.netgroup, {state.id, nil, {:update, SData.SignRev.signed(state.state), false}}) end + + # ================ + # PUBLIC INTERFACE + # ================ + + @doc""" + Return the default nickname associated to a pk, + in the form "Anonxxxxxxxx" with some bytes of the pk in hex. + """ + def default_nick(pk) do + nick_suffix = Shard.Keys.pk_display pk + "Anon" <> nick_suffix + end + + @doc""" + Find the shard process for an identity. Launches such a process + if necessary. + """ + def find_proc(pk) do + Shard.Manager.find_or_start %Manifest{pk: pk} + end + + @doc""" + Get a user's nickname from his pk + """ + def get_nick(pk) do + pid = find_proc pk + info = GenServer.call(pid, :get_info) + info.nick + end end diff --git a/shard/lib/cli/cli.ex b/shard/lib/cli/cli.ex index 85fa3fc..3b52fa5 100644 --- a/shard/lib/cli/cli.ex +++ b/shard/lib/cli/cli.ex @@ -113,18 +113,9 @@ defmodule SCLI do end defp handle_command(state, ["join", qchan]) do - pid = SApp.Chat.find_proc qchan - case pid do - nil -> - {:ok, pid} = Shard.Manifest.start %SApp.Chat.Manifest{channel: qchan} - GenServer.cast(pid, {:subscribe, self()}) - IO.puts "Joining ##{qchan} (new shard)" - %{state | room_pid: pid} - pid -> - GenServer.cast(pid, {:subscribe, self()}) - IO.puts "Switching to ##{qchan}" - %{state | room_pid: pid} - end + pid = Shard.Manager.find_or_start %SApp.Chat.Manifest{channel: qchan} + IO.puts "Switching to ##{qchan}" + %{state | room_pid: pid} end defp handle_command(state, ["pm" | people_list]) do @@ -151,22 +142,12 @@ defmodule SCLI do end end if Enum.all?(pk_list, &(&1 != :error)) do - pk_list = [state.pk | pk_list] - manifest = SApp.Chat.PrivChat.Manifest.new(pk_list) - id = SData.term_hash manifest - case Shard.Manager.find_proc id do - nil -> - {:ok, pid} = Shard.Manifest.start manifest - GenServer.cast(pid, {:subscribe, self()}) - IO.puts "Joining private conversation (new shard)." - %{state | room_pid: pid} - pid -> - GenServer.cast(pid, {:subscribe, self()}) - IO.puts "Switching to private conversation." - %{state | room_pid: pid} - end + manifest = SApp.Chat.PrivChat.Manifest.new([state.pk | pk_list]) + pid = Shard.Manager.find_or_start manifest + IO.puts "Switching to private conversation." + %{state | room_pid: pid} else - state + state end end diff --git a/shard/lib/manager.ex b/shard/lib/manager.ex index 9def229..d6b493b 100644 --- a/shard/lib/manager.ex +++ b/shard/lib/manager.ex @@ -213,6 +213,22 @@ defmodule Shard.Manager do end @doc""" + Returns the pid for a shard defined by its manifest. + Start it if it doesn't exist. + """ + def find_or_start(manifest) do + id = SData.term_hash manifest + case find_proc id do + nil -> + case Shard.Manifest.start manifest do + {:ok, pid} -> pid + {:error, :redundant} -> find_proc id + end + pid -> pid + end + end + + @doc""" Return the list of all shards. """ def list_shards() do diff --git a/shardweb/lib/shard_web/channels/room_channel.ex b/shardweb/lib/shard_web/channels/room_channel.ex index f582e06..7c3a16c 100644 --- a/shardweb/lib/shard_web/channels/room_channel.ex +++ b/shardweb/lib/shard_web/channels/room_channel.ex @@ -6,15 +6,7 @@ defmodule ShardWeb.RoomChannel do def join("room:" <> room_name, payload, socket) do if authorized?(payload) do - list = for {_chid, %SApp.Chat.Manifest{channel: chan}, chpid} <- Shard.Manager.list_shards, - do: {chan, chpid} - pid = case List.keyfind(list, room_name, 0) do - nil -> - {:ok, pid} = Shard.Manifest.start %SApp.Chat.Manifest{channel: room_name} - pid - {_, pid} -> - pid - end + pid = Shard.Manager.find_or_start %SApp.Chat.Manifest{channel: room_name} socket = assign(socket, :pid, pid) GenServer.cast(pid, {:subscribe, self()}) @@ -68,8 +60,8 @@ defmodule ShardWeb.RoomChannel do payload = Map.put(payload, "name", nick) payload = Map.put(payload, "pk16", Shard.Keys.pk_display pk) - broadcast socket, "shout", payload GenServer.cast(socket.assigns.pid, {:chat_send, pk, payload["message"]}) + broadcast socket, "shout", payload {:noreply, socket} end |