tmate-io / tmate-websocket

16 stars 13 forks source link

Tmate.MasterApi.get_named_session_prefix() fails parsing json result #7

Open pini-gh opened 3 years ago

pini-gh commented 3 years ago

Hi,

Trying to instantiate a named session, it fails with this error message in tmate-websocket's container log:

[error] GenServer #PID<0.1699.0> terminating
** (FunctionClauseError) no function clause matching in Access.get/3
    (elixir) lib/access.ex:265: Access.get("{\"prefix\":\"myusername/\"}", "prefix", nil)
    (tmate) lib/tmate/master_api.ex:32: Tmate.MasterApi.get_named_session_prefix/1
    (tmate) lib/tmate/session.ex:225: Tmate.Session.get_named_session_tokens/3
    (tmate) lib/tmate/session.ex:276: Tmate.Session.finalize_session_init/1
    (tmate) lib/tmate/session.ex:131: Tmate.Session.handle_call/3
    (stdlib) gen_server.erl:661: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:690: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Playing with the console I can easily reproduce the problem:

$ docker exec -it tmate-websocket bin/tmate remote_console
Erlang/OTP 22 [erts-10.7.2.8] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]

Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(tmate@tmate-ws.example.com)1> {:ok, result} = Tmate.MasterApi.get("/named_session_prefix", [], params: %{api_key: "tmk-mytoken"})
{:ok, "{\"prefix\":\"myusername/\"}"}
iex(tmate@tmate-ws.example.com)2> result["prefix"]
** (FunctionClauseError) no function clause matching in Access.get/3    

    The following arguments were given to Access.get/3:

        # 1
        "{\"prefix\":\"myusername/\"}"

        # 2
        "prefix"

        # 3
        nil

    Attempted function clauses (showing 5 out of 5):

        def get(-%module{} = container-, key, default)
        def get(map, key, default) when -is_map(map)-
        def get(list, key, default) when -is_list(list)- and -is_atom(key)-
        def get(list, key, _default) when -is_list(list)-
        def get(-nil-, _key, default)

    (elixir) lib/access.ex:265: Access.get/3
iex(tmate@tmate-ws.example.com)2> is_map(result)
false
iex(tmate@tmate-ws.example.com)7> is_binary(result)
true

The result object is not a map but JSON data represented as a binary string, and it has to be decoded first.

This patch fixes the problem:

diff --git a/lib/tmate/master_api.ex b/lib/tmate/master_api.ex
index acc5c33..6ee1425 100644
--- a/lib/tmate/master_api.ex
+++ b/lib/tmate/master_api.ex
@@ -29,7 +29,7 @@ defmodule Tmate.MasterApi do
   def get_named_session_prefix(api_key) do
     case get("/named_session_prefix", [], params: %{api_key: api_key}) do
       {:ok, result} ->
-        {:ok, result["prefix"]}
+        {:ok, Jason.decode!(result)["prefix"]}
       {:error, 404} ->
         {:error, :not_found}
       {:error, reason} ->