aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--shard/lib/app/chat.ex77
-rw-r--r--shard/lib/app/identity.ex45
-rw-r--r--shard/lib/app/pagestore.ex2
-rw-r--r--shard/lib/cli/cli.ex21
-rw-r--r--shardweb/lib/channels/chat_channel.ex14
-rw-r--r--shardweb/lib/controllers/chat_controller.ex2
-rw-r--r--shardweb/lib/controllers/identity_controller.ex4
-rw-r--r--shardweb/lib/templates/identity/list.html.eex2
-rw-r--r--shardweb/lib/templates/identity/view.html.eex2
-rw-r--r--shardweb/lib/templates/layout/app.html.eex8
-rw-r--r--shardweb/lib/templates/page/peer_list.html.eex4
-rw-r--r--shardweb/lib/templates/page/shard_list.html.eex2
-rw-r--r--shardweb/lib/views/layout_view.ex8
13 files changed, 148 insertions, 43 deletions
diff --git a/shard/lib/app/chat.ex b/shard/lib/app/chat.ex
index 8c55869..be3b848 100644
--- a/shard/lib/app/chat.ex
+++ b/shard/lib/app/chat.ex
@@ -31,6 +31,10 @@ defmodule SApp.Chat do
# =========
defmodule Manifest do
+ @moduledoc"""
+ Manifest for a public chat room defined by its name.
+ """
+
defstruct [:channel]
end
@@ -42,8 +46,17 @@ defmodule SApp.Chat do
defmodule PrivChat.Manifest do
+ @moduledoc"""
+ Manifest for a private chat room defined by the list of participants.
+
+ Do not instanciate this struct directly, use `new` to ensure a canonical representation.
+ """
+
defstruct [:pk_list]
+ @doc"""
+ Ensures a canonical representation by sorting pks and removing duplicates.
+ """
def new(pk_list) do
%__MODULE__{pk_list: pk_list |> Enum.sort |> Enum.uniq}
end
@@ -322,7 +335,7 @@ defmodule SApp.Chat do
end
end
- def msg_cmp({pk1, msgbin1, _sign1}, {pk2, msgbin2, _sign2}) do
+ defp msg_cmp({pk1, msgbin1, _sign1}, {pk2, msgbin2, _sign2}) do
{ts1, msg1} = SData.term_unbin msgbin1
{ts2, msg2} = SData.term_unbin msgbin2
cond do
@@ -335,4 +348,66 @@ defmodule SApp.Chat do
true -> :duplicate
end
end
+
+ # ================
+ # PUBLIC INTERFACE
+ # ================
+
+ @doc"""
+ Subscribe to notifications for this chat room.
+
+ The process calling this function will start recieving messages of the form:
+
+ {:chat_recv, manifest, {pk, msgbin, sign}}
+
+ or
+
+ {:chat_send, manifest, {pk, msgbin, sign}}
+
+ msgbin can be used in the following way:
+
+ {timestamp, message} = SData.term_unbin msgbin
+ """
+ def subscribe(shard_pid) do
+ GenServer.cast(shard_pid, {:subscribe, self()})
+ end
+
+ @doc"""
+ Send a message to a chat room.
+ """
+ def chat_send(shard_pid, pk, msg) do
+ GenServer.cast(shard_pid, {:chat_send, pk, msg})
+ end
+
+ @doc"""
+ Read the history of a chat room.
+
+ The second argument is the last message to read.
+ If nil, will read the n last messages.
+ If not nill, will read the n last messages until the specified bound.
+ """
+ def read_history(shard_pid, bound, n) do
+ GenServer.call(shard_pid, {:read_history, bound, n})
+ end
+
+ @doc"""
+ Return a shard's manifest from its pid.
+ """
+ def get_manifest(shard_pid) do
+ GenServer.call(shard_pid, :manifest)
+ end
+
+ @doc"""
+ Returns timestamp of last message if chat room has unread messages, nil otherwise.
+ """
+ def has_unread?(shard_pid) do
+ GenServer.call(shard_pid, :has_unread)
+ end
+
+ @doc"""
+ Mark all messages as read
+ """
+ def mark_read(shard_pid) do
+ GenServer.cast(shard_pid, :mark_read)
+ end
end
diff --git a/shard/lib/app/identity.ex b/shard/lib/app/identity.ex
index 95ffb92..42d1bf8 100644
--- a/shard/lib/app/identity.ex
+++ b/shard/lib/app/identity.ex
@@ -1,14 +1,29 @@
defmodule SApp.Identity do
+ @moduledoc"""
+ Shard application for keeping state associated with a user's identity.
+
+ Current functionality:
+
+ - nickname
+ - peer info: ip, port to connect to if we want a secure connection with this person
+ (used for private chat)
+
+ Future functionnality:
+
+ - friend list
+ - notifications & invites
+ """
+
use GenServer
require Logger
defmodule Manifest do
- defstruct [:pk]
- end
+ @moduledoc"""
+ Manifest for a user identity shard, defined by the public key of the user.
+ """
- defmodule State do
- defstruct [:info, :rev, :signed]
+ defstruct [:pk]
end
defimpl Shard.Manifest, for: Manifest do
@@ -17,6 +32,10 @@ defmodule SApp.Identity do
end
end
+ defmodule State do
+ defstruct [:info, :rev, :signed]
+ end
+
def start_link(pk) do
GenServer.start_link(__MODULE__, pk)
end
@@ -139,11 +158,23 @@ defmodule SApp.Identity do
end
@doc"""
+ Get the info dict of an identity shard. The pid of the shard must be given as an argument.
+ """
+ def get_info(pid) do
+ GenServer.call(pid, :get_info)
+ end
+
+ @doc"""
+ Set the info dict of an identity shard.
+ """
+ def set_info(pid, new_info) do
+ GenServer.call(pid, {:set_info, new_info})
+ 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
+ get_info(find_proc pk).nick
end
end
diff --git a/shard/lib/app/pagestore.ex b/shard/lib/app/pagestore.ex
index 86b0726..8f6be59 100644
--- a/shard/lib/app/pagestore.ex
+++ b/shard/lib/app/pagestore.ex
@@ -251,7 +251,7 @@ defmodule SApp.PageStore do
end
def ask_random_peers(state, key) do
- SNet.Group.broadcast(state.netgroup, {state.shard_id, state.path, {:get, key}}, 3)
+ SNet.Group.broadcast(state.netgroup, {state.shard_id, state.path, {:get, key}}, nmax: 3)
end
defimpl SData.PageStore do
diff --git a/shard/lib/cli/cli.ex b/shard/lib/cli/cli.ex
index 319f96b..45eeece 100644
--- a/shard/lib/cli/cli.ex
+++ b/shard/lib/cli/cli.ex
@@ -9,7 +9,7 @@ defmodule SCLI do
def run() do
for {_chid, %SApp.Chat.Manifest{}, chpid} <- Shard.Manager.list_shards do
- GenServer.cast(chpid, {:subscribe, self()})
+ SApp.Chat.subscribe(chpid)
end
pk = Shard.Keys.get_any_identity
@@ -28,14 +28,13 @@ defmodule SCLI do
nick = case id_pid do
nil -> SApp.Identity.default_nick(state.pk)
_ ->
- info = GenServer.call(id_pid, :get_info)
- info.nick
+ SApp.Identity.get_info(id_pid).nick
end
prompt = case state.room_pid do
nil -> "(no channel) #{nick}: "
_ ->
- case GenServer.call(state.room_pid, :manifest) do
+ case SApp.Chat.get_manifest(state.room_pid) do
%SApp.Chat.Manifest{channel: chan} ->
"##{chan} #{nick}: "
%SApp.Chat.PrivChat.Manifest{pk_list: pk_list} ->
@@ -57,7 +56,7 @@ defmodule SCLI do
run(state)
true ->
if str != "" do
- GenServer.cast(state.room_pid, {:chat_send, state.pk, str})
+ SApp.Chat.chat_send(state.room_pid, state.pk, str)
end
run(state)
end
@@ -102,7 +101,7 @@ defmodule SCLI do
if state.room_pid == nil do
IO.puts "Not currently on a channel!"
else
- GenServer.call(state.room_pid, {:read_history, nil, 25})
+ SApp.Chat.read_history(state.room_pid, nil, 25)
|> Enum.each(fn {{pk, msgbin, _sign}, true} ->
{ts, msg} = SData.term_unbin msgbin
nick = SApp.Identity.get_nick pk
@@ -114,14 +113,14 @@ defmodule SCLI do
defp handle_command(state, ["join", qchan]) do
pid = Shard.Manager.find_or_start %SApp.Chat.Manifest{channel: qchan}
- GenServer.cast(pid, {:subscribe, self()})
+ SApp.Chat.subscribe(pid)
IO.puts "Switching to ##{qchan}"
%{state | room_pid: pid}
end
defp handle_command(state, ["pm" | people_list]) do
known_people = for {_, %SApp.Identity.Manifest{pk: pk}, pid} <- Shard.Manager.list_shards() do
- info = GenServer.call(pid, :get_info)
+ info = SApp.Identity.get_info(pid)
{pk, info.nick}
end
pk_list = for qname <- people_list do
@@ -145,7 +144,7 @@ defmodule SCLI do
if Enum.all?(pk_list, &(&1 != :error)) do
manifest = SApp.Chat.PrivChat.Manifest.new([state.pk | pk_list])
pid = Shard.Manager.find_or_start manifest
- GenServer.cast(pid, {:subscribe, self()})
+ SApp.Chat.subscribe(pid)
IO.puts "Switching to private conversation."
%{state | room_pid: pid}
else
@@ -161,8 +160,8 @@ defmodule SCLI do
if pid == nil do
IO.puts "Sorry, we have a problem with the identity shard"
else
- info = GenServer.call(pid, :get_info)
- GenServer.call(pid, {:set_info, %{info | nick: nick}})
+ info = SApp.Identity.get_info(pid)
+ SApp.Identity.set_info(pid, %{info | nick: nick})
end
state
end
diff --git a/shardweb/lib/channels/chat_channel.ex b/shardweb/lib/channels/chat_channel.ex
index a413be1..25f1d09 100644
--- a/shardweb/lib/channels/chat_channel.ex
+++ b/shardweb/lib/channels/chat_channel.ex
@@ -9,7 +9,7 @@ defmodule ShardWeb.ChatChannel do
pid = Shard.Manager.find_or_start %SApp.Chat.Manifest{channel: room_name}
socket = assign(socket, :pid, pid)
- GenServer.cast(pid, {:subscribe, self()})
+ SApp.Chat.subscribe(pid)
send(self(), :after_join)
{:ok, socket}
@@ -27,7 +27,7 @@ defmodule ShardWeb.ChatChannel do
pid = Shard.Manager.find_or_start(SApp.Chat.PrivChat.Manifest.new(pk_list))
socket = assign(socket, :pid, pid)
- GenServer.cast(pid, {:subscribe, self()})
+ SApp.Chat.subscribe(pid)
send(self(), :after_join)
{:ok, socket}
@@ -37,7 +37,7 @@ defmodule ShardWeb.ChatChannel do
end
def handle_info(:after_join, socket) do
- GenServer.call(socket.assigns.pid, {:read_history, nil, 100})
+ SApp.Chat.read_history(socket.assigns.pid, nil, 100)
|> Enum.each(fn {{pk, msgbin, _sign}, true} ->
{_ts, msg} = SData.term_unbin msgbin
nick = SApp.Identity.get_nick pk
@@ -47,7 +47,7 @@ defmodule ShardWeb.ChatChannel do
message: msg,
})
end)
- GenServer.cast(socket.assigns.pid, :mark_read)
+ SApp.Chat.mark_read(socket.assigns.pid)
{:noreply, socket}
end
@@ -58,12 +58,12 @@ defmodule ShardWeb.ChatChannel do
push socket, "shout", %{"name" => nick,
"pk16" => Shard.Keys.pk_display(pk),
"message" => msg}
- GenServer.cast(socket.assigns.pid, :mark_read)
+ SApp.Chat.mark_read(socket.assigns.pid)
{:noreply, socket}
end
def handle_info({:chat_send, _, _}, socket) do
- GenServer.cast(socket.assigns.pid, :mark_read)
+ SApp.Chat.mark_read(socket.assigns.pid)
{:noreply, socket}
end
@@ -81,7 +81,7 @@ defmodule ShardWeb.ChatChannel do
payload = Map.put(payload, "name", nick)
payload = Map.put(payload, "pk16", Shard.Keys.pk_display pk)
- GenServer.cast(socket.assigns.pid, {:chat_send, pk, payload["message"]})
+ SApp.Chat.chat_send(socket.assigns.pid, pk, payload["message"])
broadcast socket, "shout", payload
{:noreply, socket}
end
diff --git a/shardweb/lib/controllers/chat_controller.ex b/shardweb/lib/controllers/chat_controller.ex
index 31b80ba..75f2f18 100644
--- a/shardweb/lib/controllers/chat_controller.ex
+++ b/shardweb/lib/controllers/chat_controller.ex
@@ -14,7 +14,7 @@ defmodule ShardWeb.ChatController do
def privchat(conn, %{"people_list" => people_list}) do
known_people = for {_, %SApp.Identity.Manifest{pk: pk}, pid} <- Shard.Manager.list_shards() do
- info = GenServer.call(pid, :get_info)
+ info = SApp.Identity.get_info(pid)
{pk, info.nick}
end
diff --git a/shardweb/lib/controllers/identity_controller.ex b/shardweb/lib/controllers/identity_controller.ex
index dd254bb..962a888 100644
--- a/shardweb/lib/controllers/identity_controller.ex
+++ b/shardweb/lib/controllers/identity_controller.ex
@@ -27,9 +27,9 @@ defmodule ShardWeb.IdentityController do
def update(conn, params) do
pid = SApp.Identity.find_proc(conn.assigns.pk)
- info = GenServer.call(pid, :get_info)
+ info = SApp.Identity.get_info(pid)
info = %{info | nick: params["nick"]}
- GenServer.call(pid, {:set_info, info})
+ SApp.Identity.set_info(pid, info)
redirect conn, to: identity_path(conn, :self)
end
diff --git a/shardweb/lib/templates/identity/list.html.eex b/shardweb/lib/templates/identity/list.html.eex
index 6437f9c..19dba2d 100644
--- a/shardweb/lib/templates/identity/list.html.eex
+++ b/shardweb/lib/templates/identity/list.html.eex
@@ -25,7 +25,7 @@
</tr>
<%= for {_id, manifest, pid} <- people_list() do %>
<tr>
- <td><i class="fa fa-user"></i> <%= GenServer.call(pid, :get_info).nick %>
+ <td><i class="fa fa-user"></i> <%= SApp.Identity.get_info(pid).nick %>
<%= if manifest.pk == @pk do %>
<span class="badge badge-success"><i class="fa fa-user"></i> myself</span>
<% end %>
diff --git a/shardweb/lib/templates/identity/view.html.eex b/shardweb/lib/templates/identity/view.html.eex
index 8bb8ca2..58be7e7 100644
--- a/shardweb/lib/templates/identity/view.html.eex
+++ b/shardweb/lib/templates/identity/view.html.eex
@@ -19,7 +19,7 @@
<%= render ShardWeb.LayoutView, "flashes.html", assigns %>
<pre>
- <%= inspect((GenServer.call(@pid, :get_info)), pretty: true, width: 40) %>
+ <%= inspect(SApp.Identity.get_info(@pid), pretty: true, width: 40) %>
</pre>
diff --git a/shardweb/lib/templates/layout/app.html.eex b/shardweb/lib/templates/layout/app.html.eex
index d96bdeb..6cedcaf 100644
--- a/shardweb/lib/templates/layout/app.html.eex
+++ b/shardweb/lib/templates/layout/app.html.eex
@@ -61,7 +61,7 @@
<b class="caret"></b>
</a>
<ul class="dropdown-menu message-dropdown">
- <%= for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- sur do %>
+ <%= for {_id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- sur do %>
<li class="message-preview">
<a href="<%= chat_path(@conn, :privchat, str_of_pk_list(@conn, pk_list)) %>">
<div class="media">
@@ -137,7 +137,7 @@
<%= for {id, %SApp.Chat.Manifest{channel: name}, pid} <- shard_list() do %>
<li class="<%= if @shard == id do "custom_active" else "" end %>">
<a href="<%= chat_path(@conn, :chat, name) %>">
- <%= if GenServer.call(pid, :has_unread) != nil do %>
+ <%= if SApp.Chat.has_unread?(pid) != nil do %>
<span class="have_unread">#<%= name %></span>
<% else %>
#<%= name %>
@@ -159,7 +159,7 @@
<%= for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- shard_list() do %>
<li class="<%= if id == @shard do "custom_active" else "" end %>">
<a href="<%= chat_path(@conn, :privchat, str_of_pk_list(@conn, pk_list)) %>">
- <%= if GenServer.call(pid, :has_unread) != nil do %>
+ <%= if SApp.Chat.has_unread?(pid) != nil do %>
<span class="have_unread"><%= nicks_of_pk_list(@conn, pk_list) %></span>
<% else %>
<%= nicks_of_pk_list(@conn, pk_list) %>
@@ -171,7 +171,7 @@
<% end %>
</li>
<li class="<%= if @view_module == ShardWeb.PageView and @view_template == "peer_list.html" do "active" else "" end %>">
- <a href="<%= page_path(@conn, :peer_list) %>"><i class="fa fa-fw fa-globe"></i> Peer list</a>
+ <a href="<%= page_path(@conn, :peer_list) %>"><i class="fa fa-fw fa-server"></i> Peer list</a>
</li>
<li>
<a href="#"><i class="fa fa-fw fa-gear"></i> Settings</a>
diff --git a/shardweb/lib/templates/page/peer_list.html.eex b/shardweb/lib/templates/page/peer_list.html.eex
index ff6479f..09060a7 100644
--- a/shardweb/lib/templates/page/peer_list.html.eex
+++ b/shardweb/lib/templates/page/peer_list.html.eex
@@ -10,7 +10,7 @@
<i class="fa fa-dashboard"></i> Dashboard
</li>
<li class="active">
- <i class="fa fa-globe"></i> Peer list
+ <i class="fa fa-server"></i> Peer list
</li>
</ol>
</div>
@@ -29,7 +29,7 @@
<tr>
<td>
<%= case auth do %>
- <% nil -> %>(anonymous)
+ <% nil -> %><i class="fa fa-globe"></i> (anonymous)
<% %SNet.Auth{his_pk: his_pk} -> %>
<i class="fa fa-user"></i>
<%= SApp.Identity.get_nick(his_pk) %>
diff --git a/shardweb/lib/templates/page/shard_list.html.eex b/shardweb/lib/templates/page/shard_list.html.eex
index 012223a..cc23205 100644
--- a/shardweb/lib/templates/page/shard_list.html.eex
+++ b/shardweb/lib/templates/page/shard_list.html.eex
@@ -30,7 +30,7 @@
<td>
<%= case manifest do %>
<% %SApp.Identity.Manifest{pk: pk} -> %><i class="fa fa-user"></i>
- <%= GenServer.call(pid, :get_info).nick %>
+ <%= SApp.Identity.get_info(pid).nick %>
<a href="<%= identity_path(@conn, :view, pk|>Base.encode16) %>">
<small><%= Shard.Keys.pk_display pk %></small>
</a>
diff --git a/shardweb/lib/views/layout_view.ex b/shardweb/lib/views/layout_view.ex
index 990df55..d554804 100644
--- a/shardweb/lib/views/layout_view.ex
+++ b/shardweb/lib/views/layout_view.ex
@@ -26,7 +26,7 @@ defmodule ShardWeb.LayoutView do
end
def chat_shard_last_msg(pid) do
- [{{_, msgbin, _}, true}] = GenServer.call(pid, {:read_history, nil, 1})
+ [{{_, msgbin, _}, true}] = SApp.Chat.read_history(pid, nil, 1)
{_, msg} = SData.term_unbin msgbin
msg
end
@@ -34,14 +34,14 @@ defmodule ShardWeb.LayoutView do
def privchat_with_unread(conn) do
for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- shard_list(),
conn.assigns.pk in pk_list,
- unread_time = GenServer.call(pid, :has_unread),
+ unread_time = SApp.Chat.has_unread?(pid),
unread_time != nil,
do: {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid}
end
- def chat_with_unread(conn) do
+ def chat_with_unread(_conn) do
for {id, %SApp.Chat.Manifest{channel: c}, pid} <- shard_list(),
- unread_time = GenServer.call(pid, :has_unread),
+ unread_time = SApp.Chat.has_unread?(pid),
unread_time != nil,
do: {id, %SApp.Chat.Manifest{channel: c}, pid}
end