diff options
-rw-r--r-- | shard/lib/app/chat.ex | 2 | ||||
-rw-r--r-- | shardweb/assets/js/app.js | 6 | ||||
-rw-r--r-- | shardweb/lib/channels/chat_channel.ex | 20 | ||||
-rw-r--r-- | shardweb/lib/channels/user_socket.ex | 3 | ||||
-rw-r--r-- | shardweb/lib/controllers/chat_controller.ex | 48 | ||||
-rw-r--r-- | shardweb/lib/controllers/identity_controller.ex | 14 | ||||
-rw-r--r-- | shardweb/lib/controllers/page_controller.ex | 2 | ||||
-rw-r--r-- | shardweb/lib/router.ex | 6 | ||||
-rw-r--r-- | shardweb/lib/templates/chat/chat.html.eex | 31 | ||||
-rw-r--r-- | shardweb/lib/templates/identity/list.html.eex | 12 | ||||
-rw-r--r-- | shardweb/lib/templates/layout/app.html.eex | 27 | ||||
-rw-r--r-- | shardweb/lib/templates/page/shard_list.html.eex | 17 | ||||
-rw-r--r-- | shardweb/lib/views/layout_view.ex | 20 | ||||
-rw-r--r-- | 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 @@ <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 |