From 0d358f6f699a5ce04ffe1bccf4f375b5f321391c Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 12 Oct 2018 15:52:42 +0200 Subject: Private chat interface --- shard/lib/app/chat.ex | 2 +- shardweb/assets/js/app.js | 6 ++-- shardweb/lib/channels/chat_channel.ex | 20 ++++++++++- shardweb/lib/channels/user_socket.ex | 3 +- shardweb/lib/controllers/chat_controller.ex | 48 ++++++++++++++++++++++--- shardweb/lib/controllers/identity_controller.ex | 14 +++++--- shardweb/lib/controllers/page_controller.ex | 2 +- shardweb/lib/router.ex | 6 ++-- shardweb/lib/templates/chat/chat.html.eex | 31 +++++++++++----- shardweb/lib/templates/identity/list.html.eex | 12 ++++++- shardweb/lib/templates/layout/app.html.eex | 27 +++++++++----- shardweb/lib/templates/page/shard_list.html.eex | 17 +++++++-- shardweb/lib/views/layout_view.ex | 20 +++++++++++ shardweb/lib/views/page_view.ex | 1 + 14 files changed, 169 insertions(+), 40 deletions(-) diff --git a/shard/lib/app/chat.ex b/shard/lib/app/chat.ex index ea210d8..d8ba5da 100644 --- a/shard/lib/app/chat.ex +++ b/shard/lib/app/chat.ex @@ -45,7 +45,7 @@ defmodule SApp.Chat do defstruct [:pk_list] def new(pk_list) do - %__MODULE__{pk_list: Enum.sort(pk_list)} + %__MODULE__{pk_list: pk_list |> Enum.sort |> Enum.uniq} end end 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 @@

- #<%= @room %> - public chat room + <%= if @public do %> + #<%= @chan %> + public chat room + <% else %> + #<%= @nicks %> + private chat + <% end %>

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 @@ + <%= for {_id, manifest, pid} <- people_list() do %> - + + <% 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 @@
User name Public key
<%= GenServer.call(pid, :get_info).nick %> <%= GenServer.call(pid, :get_info).nick %> + <%= if manifest.pk == @pk do %> + myself + <% end %> + + <%= if manifest.pk != @pk do %> + PM + <% end %> + <%= manifest.pk |> Base.encode16 %>