aboutsummaryrefslogtreecommitdiff
path: root/shardweb
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2018-10-12 15:52:42 +0200
committerAlex Auvolat <alex@adnab.me>2018-10-12 15:52:42 +0200
commit0d358f6f699a5ce04ffe1bccf4f375b5f321391c (patch)
treeb90a1093b3ac0cd1e7d3643abb34e87078b6072e /shardweb
parent1e91dc596fd2f7fdd96b7fd2fc50724f93e46529 (diff)
downloadshard-0d358f6f699a5ce04ffe1bccf4f375b5f321391c.tar.gz
shard-0d358f6f699a5ce04ffe1bccf4f375b5f321391c.zip
Private chat interface
Diffstat (limited to 'shardweb')
-rw-r--r--shardweb/assets/js/app.js6
-rw-r--r--shardweb/lib/channels/chat_channel.ex20
-rw-r--r--shardweb/lib/channels/user_socket.ex3
-rw-r--r--shardweb/lib/controllers/chat_controller.ex48
-rw-r--r--shardweb/lib/controllers/identity_controller.ex14
-rw-r--r--shardweb/lib/controllers/page_controller.ex2
-rw-r--r--shardweb/lib/router.ex6
-rw-r--r--shardweb/lib/templates/chat/chat.html.eex31
-rw-r--r--shardweb/lib/templates/identity/list.html.eex12
-rw-r--r--shardweb/lib/templates/layout/app.html.eex27
-rw-r--r--shardweb/lib/templates/page/shard_list.html.eex17
-rw-r--r--shardweb/lib/views/layout_view.ex20
-rw-r--r--shardweb/lib/views/page_view.ex1
13 files changed, 168 insertions, 39 deletions
diff --git a/shardweb/assets/js/app.js b/shardweb/assets/js/app.js
index 53a0112..3adae5a 100644
--- a/shardweb/assets/js/app.js
+++ b/shardweb/assets/js/app.js
@@ -20,10 +20,10 @@ import "phoenix_html"
import socket from "./socket"
-var room_name = window.Gon.getAsset('chat_room');
-if (room_name != undefined)
+var chat_channel = window.Gon.getAsset('chat_channel');
+if (chat_channel != undefined)
{
- var channel = socket.channel('room:' + room_name, {}); // connect to chat "room"
+ var channel = socket.channel(chat_channel, {}); // connect to chat "room"
channel.on('shout', function (payload) { // listen to the 'shout' event
var li = document.createElement("li"); // creaet new list item DOM element
diff --git a/shardweb/lib/channels/chat_channel.ex b/shardweb/lib/channels/chat_channel.ex
index 3e51c3a..f898602 100644
--- a/shardweb/lib/channels/chat_channel.ex
+++ b/shardweb/lib/channels/chat_channel.ex
@@ -3,7 +3,7 @@ defmodule ShardWeb.ChatChannel do
require Logger
- def join("room:" <> room_name, payload, socket) do
+ def join("chat:" <> room_name, payload, socket) do
if authorized?(payload) do
pid = Shard.Manager.find_or_start %SApp.Chat.Manifest{channel: room_name}
@@ -18,6 +18,24 @@ defmodule ShardWeb.ChatChannel do
end
end
+ def join("privchat:" <> room_name, payload, socket) do
+ if authorized?(payload) do
+
+ pk_list = room_name |> String.split(",") |> Enum.map(&Base.decode16!/1)
+ pk_list = [socket.assigns.pk | pk_list] |> Enum.sort() |> Enum.uniq()
+
+ pid = Shard.Manager.find_or_start(SApp.Chat.PrivChat.Manifest.new(pk_list))
+ socket = assign(socket, :pid, pid)
+
+ GenServer.cast(pid, {:subscribe, self()})
+ send(self(), :after_join)
+
+ {:ok, socket}
+ else
+ {:error, %{reason: "unauthorized"}}
+ end
+ end
+
def handle_info(:after_join, socket) do
GenServer.call(socket.assigns.pid, {:read_history, nil, 100})
|> Enum.each(fn {{pk, msgbin, _sign}, true} ->
diff --git a/shardweb/lib/channels/user_socket.ex b/shardweb/lib/channels/user_socket.ex
index b4136bd..04cc584 100644
--- a/shardweb/lib/channels/user_socket.ex
+++ b/shardweb/lib/channels/user_socket.ex
@@ -4,7 +4,8 @@ defmodule ShardWeb.UserSocket do
require Logger
## Channels
- channel "room:*", ShardWeb.ChatChannel
+ channel "chat:*", ShardWeb.ChatChannel
+ channel "privchat:*", ShardWeb.ChatChannel
## Transports
transport :websocket, Phoenix.Transports.WebSocket
diff --git a/shardweb/lib/controllers/chat_controller.ex b/shardweb/lib/controllers/chat_controller.ex
index 45b7d34..31b80ba 100644
--- a/shardweb/lib/controllers/chat_controller.ex
+++ b/shardweb/lib/controllers/chat_controller.ex
@@ -1,13 +1,51 @@
defmodule ShardWeb.ChatController do
use ShardWeb, :controller
- def chat(conn, %{"room" => room}) do
- conn = put_gon(conn, chat_room: room)
+ def chat(conn, %{"chan" => chan}) do
+ conn = put_gon(conn, chat_channel: "chat:" <> chan)
+
+ shard = %SApp.Chat.Manifest{channel: chan} |> SData.term_hash
+
render conn, "chat.html",
- room: room
+ public: true,
+ shard: shard,
+ chan: chan
end
- def privchat(_conn, %{"pk" => _pk}) do
- # TODO
+ 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)
+ {pk, info.nick}
+ end
+
+ pk_list = for qname <- String.split(people_list, ",") do
+ candidates = for {pk, nick} <- known_people,
+ :binary.longest_common_prefix([qname, nick]) == byte_size(qname)
+ or :binary.longest_common_prefix([qname, Shard.Keys.pk_display pk]) == byte_size(qname)
+ or Base.decode16(qname) == {:ok, pk},
+ do: {pk, nick}
+ case candidates do
+ [] -> :error
+ [{pk, _}] -> pk
+ _ -> :error
+ end
+ end
+
+ if Enum.all?(pk_list, &(&1 != :error)) do
+ pk_list_str = pk_list |> Enum.map(&Base.encode16/1) |> Enum.join(",")
+ conn = put_gon(conn, chat_channel: "privchat:" <> pk_list_str)
+ name = pk_list
+ |> Enum.map(&SApp.Identity.get_nick/1)
+ |> Enum.join(", ")
+
+ shard = [conn.assigns.pk | pk_list] |> SApp.Chat.PrivChat.Manifest.new |> SData.term_hash
+
+ render conn, "chat.html",
+ public: false,
+ shard: shard,
+ nicks: name
+ else
+ render conn, ShardWeb.ErrorView, "404.html"
+ end
end
end
diff --git a/shardweb/lib/controllers/identity_controller.ex b/shardweb/lib/controllers/identity_controller.ex
index fdaefd0..3c04fe8 100644
--- a/shardweb/lib/controllers/identity_controller.ex
+++ b/shardweb/lib/controllers/identity_controller.ex
@@ -9,12 +9,16 @@ defmodule ShardWeb.IdentityController do
render conn, "self.html"
end
+ def view(conn, %{"pk" => pk}) do
+ #TODO
+ end
+
def update(conn, params) do
pid = SApp.Identity.find_proc(conn.assigns.pk)
info = GenServer.call(pid, :get_info)
info = %{info | nick: params["nick"]}
GenServer.call(pid, {:set_info, info})
- redirect conn, to: identity_path(conn, :view)
+ redirect conn, to: identity_path(conn, :self)
end
def switch(conn, params) do
@@ -23,22 +27,22 @@ defmodule ShardWeb.IdentityController do
if Shard.Keys.have_sk? pk do
conn
|> put_session(:pk, pk)
- |> redirect(to: identity_path(conn, :view))
+ |> redirect(to: identity_path(conn, :self))
else
conn
|> put_flash(:error, "No secret key found")
- |> render("view.html")
+ |> render("self.html")
end
_ ->
conn
|> put_flash(:error, "Bad argument")
- |> render("view.html")
+ |> render("self.html")
end
end
def create(conn, _params) do
pk = Shard.Keys.new_identity
conn = put_session(conn, :pk, pk)
- redirect conn, to: identity_path(conn, :view)
+ redirect conn, to: identity_path(conn, :self)
end
end
diff --git a/shardweb/lib/controllers/page_controller.ex b/shardweb/lib/controllers/page_controller.ex
index ebe2099..5c90416 100644
--- a/shardweb/lib/controllers/page_controller.ex
+++ b/shardweb/lib/controllers/page_controller.ex
@@ -26,6 +26,6 @@ defmodule ShardWeb.PageController do
rescue
_ -> nil
end
- redirect conn, to: page_path(conn, :index)
+ redirect conn, to: page_path(conn, :peer_list)
end
end
diff --git a/shardweb/lib/router.ex b/shardweb/lib/router.ex
index 43de0da..2c69b8c 100644
--- a/shardweb/lib/router.ex
+++ b/shardweb/lib/router.ex
@@ -23,13 +23,14 @@ defmodule ShardWeb.Router do
get "/dashboard", PageController, :shard_list
get "/people", IdentityController, :list
+ get "/people/:pk", IdentityController, :view
get "/identity", IdentityController, :self
post "/identity", IdentityController, :update
post "/identity/switch", IdentityController, :switch
post "/identity/create", IdentityController, :create
- get "/chat/:room", ChatController, :chat
- get "/pm/:pk", ChatController, :privchat
+ get "/chat/:chan", ChatController, :chat
+ get "/pm/:people_list", ChatController, :privchat
end
# Other scopes may use custom stacks.
@@ -50,6 +51,7 @@ defmodule ShardWeb.Router do
conn
|> assign(:pk, pk)
|> assign(:nick, nick)
+ |> assign(:shard, nil)
|> PhoenixGon.Controller.put_gon(pk: (pk|>Base.encode16))
end
diff --git a/shardweb/lib/templates/chat/chat.html.eex b/shardweb/lib/templates/chat/chat.html.eex
index 86c2fb6..8a43acf 100644
--- a/shardweb/lib/templates/chat/chat.html.eex
+++ b/shardweb/lib/templates/chat/chat.html.eex
@@ -2,17 +2,32 @@
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
- #<%= @room %>
- <small>public chat room</small>
+ <%= if @public do %>
+ #<%= @chan %>
+ <small>public chat room</small>
+ <% else %>
+ #<%= @nicks %>
+ <small>private chat</small>
+ <% end %>
</h1>
<ol class="breadcrumb">
- <li>
- <i class="fa fa-comments"></i> Chat rooms
- </li>
- <li class="active">
- <i class="fa fa-comments"></i> #<%= @room %>
- </li>
+
+ <%= if @public do %>
+ <li>
+ <i class="fa fa-comments"></i> Chat rooms
+ </li>
+ <li class="active">
+ <i class="fa fa-comments"></i> #<%= @chan %>
+ </li>
+ <% else %>
+ <li>
+ <i class="fa fa-user"></i> Private chat
+ </li>
+ <li class="active">
+ <i class="fa fa-comments"></i> <%= @nicks %>
+ </li>
+ <% end %>
</ol>
</div>
</div>
diff --git a/shardweb/lib/templates/identity/list.html.eex b/shardweb/lib/templates/identity/list.html.eex
index 1354264..007af3d 100644
--- a/shardweb/lib/templates/identity/list.html.eex
+++ b/shardweb/lib/templates/identity/list.html.eex
@@ -20,11 +20,21 @@
<table class="table table-striped">
<tr>
<th>User name</th>
+ <th></th>
<th>Public key</th>
</tr>
<%= for {_id, manifest, pid} <- people_list() do %>
<tr>
- <td><i class="fa fa-user"></i> <%= GenServer.call(pid, :get_info).nick %> </td>
+ <td><i class="fa fa-user"></i> <%= GenServer.call(pid, :get_info).nick %>
+ <%= if manifest.pk == @pk do %>
+ <span class="badge badge-success"><i class="fa fa-user"></i> myself</span>
+ <% end %>
+ </td>
+ <td>
+ <%= if manifest.pk != @pk do %>
+ <a class="btn btn-xs btn-primary" href="<%= chat_path(@conn, :privchat, manifest.pk |> Base.encode16) %>"><i class="fa fa-comments"></i> PM</a>
+ <% end %>
+ </td>
<td><small><%= manifest.pk |> Base.encode16 %></small></td>
</tr>
<% end %>
diff --git a/shardweb/lib/templates/layout/app.html.eex b/shardweb/lib/templates/layout/app.html.eex
index 5a087f2..f49c8e6 100644
--- a/shardweb/lib/templates/layout/app.html.eex
+++ b/shardweb/lib/templates/layout/app.html.eex
@@ -153,28 +153,37 @@
<!-- Sidebar Menu Items - These collapse to the responsive navigation menu on small screens -->
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav side-nav">
- <li class="<%= if @view_module == ShardWeb.IdentityView do "active" else "" end %>">
+ <li class="<%= if @view_module == ShardWeb.IdentityView and @view_template == "self.html" do "active" else "" end %>">
<a href="<%= identity_path(@conn, :self) %>"><i class="fa fa-fw fa-user"></i> <%= @nick %></a>
</li>
- <li class="<%= if @view_module == ShardWeb.RoomView do "active" else "" end %>">
+ <li class="<%= if @view_module == ShardWeb.ChatView and @view_template == "chat.html" and @public do "active" else "" end %>">
<a href="javascript:;" data-toggle="collapse" data-target="#demo"><i class="fa fa-fw fa-comments"></i> Chat rooms <i class="fa fa-fw fa-caret-down"></i></a>
- <ul id="demo" class="<%= if @view_module != ShardWeb.RoomView do "collapse" else "" end %>">
+ <ul id="demo" class="<%= if not (@view_module == ShardWeb.ChatView and @view_template == "chat.html" and @public) do "collapse" else "" end %>">
- <%= for {_, %SApp.Chat.Manifest{channel: name}, _} <- shard_list() do %>
- <li class="<%= if @view_module == ShardWeb.RoomView and @room == name do "custom_active" else "" end %>">
+ <%= for {id, %SApp.Chat.Manifest{channel: name}, _} <- shard_list() do %>
+ <li class="<%= if @shard == id do "custom_active" else "" end %>">
<a href="<%= chat_path(@conn, :chat, name) %>">#<%= name %></a>
</li>
<% end %>
<li>
- <a href="#" onclick="if(new_room=prompt('Enter name of room to join, without preceding # sign:'))window.location.href='/room/'+new_room;">Join room</a>
+ <a href="#" onclick="if(new_room=prompt('Enter name of room to join, without preceding # sign:'))window.location.href='<%= chat_path(@conn, :chat, "") %>'+new_room;">Join room</a>
</li>
</ul>
</li>
- <li>
- <a href="<%= identity_path(@conn, :list) %>"><i class="fa fa-fw fa-users"></i> People</a>
+ <li class="<%= if (@view_module == ShardWeb.IdentityView and @view_template == "list.html") or (@view_module == ShardWeb.ChatView and @view_template == "chat.html" and not @public) do "active" else "" end %>">
+ <a href="<%= identity_path(@conn, :list) %>"><i class="fa fa-fw fa-users"></i> People<i class="fa fa-fw fa-caret-down"></i></a>
+ <%= if (@view_module == ShardWeb.IdentityView and @view_template == "list.html") or (@view_module == ShardWeb.ChatView and @view_template == "chat.html" and not @public) do %>
+ <ul>
+ <%= for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, _} <- 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)) %>"><%= nicks_of_pk_list(@conn, pk_list) %></a>
+ </li>
+ <% end %>
+ </ul>
+ <% 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>
@@ -182,7 +191,7 @@
<li>
<a href="#"><i class="fa fa-fw fa-gear"></i> Settings</a>
</li>
- <li>
+ <li class="<%= if @view_module == ShardWeb.PageView and @view_template == "shard_list.html" do "active" else "" end %>">
<a href="<%= page_path(@conn, :shard_list) %>"><i class="fa fa-fw fa-dashboard"></i> Dashboard</a>
</li>
</ul>
diff --git a/shardweb/lib/templates/page/shard_list.html.eex b/shardweb/lib/templates/page/shard_list.html.eex
index a0648d3..485bfa1 100644
--- a/shardweb/lib/templates/page/shard_list.html.eex
+++ b/shardweb/lib/templates/page/shard_list.html.eex
@@ -31,10 +31,21 @@
<%= case manifest do %>
<% %SApp.Identity.Manifest{pk: pk} -> %><i class="fa fa-user"></i>
<%= GenServer.call(pid, :get_info).nick %>
- <small><%= Shard.Keys.pk_display pk %></small>
- <% %SApp.Chat.Manifest{channel: chan} -> %><i class="fa fa-comments"></i> #<%= chan %>
+ <a href="<%= identity_path(@conn, :view, pk|>Base.encode16) %>">
+ <small><%= Shard.Keys.pk_display pk %></small>
+ </a>
+
+ <% %SApp.Chat.Manifest{channel: chan} -> %><i class="fa fa-comments"></i>
+ <a href="<%= chat_path(@conn, :chat, chan) %>">
+ #<%= chan %>
+ </a>
+
<% %SApp.Chat.PrivChat.Manifest{pk_list: pk_list} -> %><i class="fa fa-comment"></i>
- <%= pk_list |> Enum.map(&SApp.Identity.get_nick/1) |> Enum.join(", ") %>
+ <a href="<%= chat_path(@conn, :privchat,
+ (pk_list |> Enum.filter(&(&1!=@pk)) |> Enum.map(&Base.encode16/1) |> Enum.join(","))) %>">
+ @<%= pk_list |> Enum.filter(&(&1!=@pk)) |> Enum.map(&SApp.Identity.get_nick/1) |> Enum.join(", ") %>
+ </a>
+
<% x -> %> <%= inspect x %>
<% end %>
</td>
diff --git a/shardweb/lib/views/layout_view.ex b/shardweb/lib/views/layout_view.ex
index 2b12323..317d405 100644
--- a/shardweb/lib/views/layout_view.ex
+++ b/shardweb/lib/views/layout_view.ex
@@ -4,4 +4,24 @@ defmodule ShardWeb.LayoutView do
def shard_list do
Shard.Manager.list_shards
end
+
+ def str_of_pk_list(conn, pk_list) do
+ case pk_list
+ |> Enum.filter(&(&1 != conn.assigns.pk))
+ |> Enum.map(&Base.encode16/1)
+ do
+ [] -> conn.assigns.pk |> Base.encode16
+ l -> Enum.join(l, ",")
+ end
+ end
+
+ def nicks_of_pk_list(conn, pk_list) do
+ case pk_list
+ |> Enum.filter(&(&1 != conn.assigns.pk))
+ |> Enum.map(&SApp.Identity.get_nick/1)
+ do
+ [] -> "(myself)"
+ l -> Enum.join(l, ", ")
+ end
+ end
end
diff --git a/shardweb/lib/views/page_view.ex b/shardweb/lib/views/page_view.ex
index eb88617..9d7dd6d 100644
--- a/shardweb/lib/views/page_view.ex
+++ b/shardweb/lib/views/page_view.ex
@@ -14,5 +14,6 @@ defmodule ShardWeb.PageView do
def shard_list do
Shard.Manager.list_shards
+ |> Enum.sort_by(fn {_,m,_} -> m end)
end
end