aboutsummaryrefslogblamecommitdiff
path: root/shard/lib/cli/cli.ex
blob: 2e35e45d79daac9fd4d5fda3f341dd07c6abc64c (plain) (tree)
1
2
3
4
5
6
7
8
9
                 



                                                       



                                       
              
                                                                             


                                                 
                                    
                                                   

     
                    

                     













                                                 

                                     
                                                                                      



                                          




                                                                 

                                              
              
                       
                                                                     
           
                  


       

                           



                                                                                                                             







                           
                                                            

                                                       
                                    
         

     
                                         
                                     
 
                                                                                           

                        
         

     

                                         

                                           

                                                              



                                                                                                                     
       
         

     


                                                
            
                                                                             
                                                 

                                
                                        
                                
       

     











                                                                

     
                                     
                             
         

     
defmodule SCLI do
  @moduledoc """
  Small command line interface for the chat application
  """

  defmodule State do
    defstruct [:room_pid, :id_pid, :pk]
  end

  def run() do
    for {_chid, %SApp.Chat.Manifest{}, chpid} <- Shard.Manager.list_shards do
      GenServer.cast(chpid, {:subscribe, self()})
    end

    pk = Shard.Keys.get_any_identity
    run(%State{room_pid: nil, id_pid: nil, pk: pk})
  end

  defp run(state) do
    handle_messages()

    id_pid = case state.id_pid do
      nil -> SApp.Identity.find_proc(state.pk)
      x -> x
    end
    state = put_in(state.id_pid, id_pid)

    nick = case id_pid do
      nil -> SApp.Identity.default_nick(state.pk)
      _ ->
        info = GenServer.call(id_pid, :get_info)
        info.nick
    end

    prompt = case state.room_pid do
      nil -> "(no channel) #{nick}: "
      _ -> 
        %SApp.Chat.Manifest{channel: chan} = GenServer.call(state.room_pid, :manifest)
        "##{chan} #{nick}: "
    end

    str = prompt |> IO.gets |> String.trim
    cond do
      str == "/quit" ->
        nil
      String.slice(str, 0..0) == "/" ->
        command = str |> String.slice(1..-1) |> String.split(" ")
        state = handle_command(state, command)
        run(state)
      true -> 
        if str != "" do
          GenServer.cast(state.room_pid, {:chat_send, state.pk, str})
        end
        run(state)
    end
  end

  defp handle_messages() do
    receive do
      {:chat_recv, chan, {pk, msgbin, _sign}} ->
        {ts, msg} = SData.term_unbin msgbin
        nick = SApp.Identity.get_nick pk
        IO.puts "#{ts |> DateTime.from_unix! |> DateTime.to_iso8601}  ##{chan}  <#{nick} #{Shard.Keys.pk_display pk}> #{msg}"
        handle_messages()
      {:chat_send, _, _} ->
        # do nothing
        handle_messages()
    after 10 -> nil
    end
  end

  defp handle_command(state, ["connect", ipstr, portstr]) do
    {:ok, ip} = :inet.parse_address (to_charlist ipstr)
    {port, _} = Integer.parse portstr
    Shard.Manager.add_peer(ip, port)
    state
  end

  defp handle_command(state, ["list"]) do
    IO.puts "List of known channels:"

    for {_chid, %SApp.Chat.Manifest{channel: chan}, _chpid} <- Shard.Manager.list_shards do
      IO.puts "##{chan}"
    end
    state
  end

  defp handle_command(state, ["hist"]) do
    if state.room_pid == nil do
      IO.puts "Not currently on a channel!"
    else
      GenServer.call(state.room_pid, {:read_history, nil, 25})
      |> Enum.each(fn {{pk, msgbin, _sign}, true} ->
          {ts, msg} = SData.term_unbin msgbin
          nick = SApp.Identity.get_nick pk
          IO.puts "#{ts |> DateTime.from_unix! |> DateTime.to_iso8601}  <#{nick} #{Shard.Keys.pk_display pk}> #{msg}"
        end)
    end
    state
  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()})
        %{state | room_pid: pid}
      pid ->
        IO.puts "Switching to ##{qchan}"
        %{state | room_pid: pid}
    end
  end

  defp handle_command(state, ["nick", nick]) do
    pid = case state.id_pid do
      nil -> SApp.Identity.find_proc state.pk
      x -> x
    end
    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}})
    end
    state
  end

  defp handle_command(state, _cmd) do
    IO.puts "Invalid command"
    state
  end
end