defmodule Client.Directline do @moduledoc """ A Microsoft Directline Client """ alias Direxion.{Util, Config} @behaviour Direxion.ClientBehaviour @doc """ Starts a conversation with directline Returns a tuple containing the status of request and the conversation ID """ @spec start_conversation() :: tuple() def start_conversation() do url = "https://directline.botframework.com/v3/directline/conversations" headers = Util.generate_directline_header() case HTTPoison.post(url, "{}", headers) do {:ok, %HTTPoison.Response{status_code: 201, body: body}} -> conversation_id = body |> Poison.decode!() |> Map.get("conversationId") {:ok, conversation_id} {:ok, _} -> {:error, "Error Starting Conversation"} {:error, %HTTPoison.Error{reason: reason}} -> {:error, reason} end end @doc """ Sends an activity to a given conversation Parameters: * conversation_id - The Conversation ID * activity - The activity payload Returns a tuple containing the status of request and the activity ID """ @spec send_activity(String.t(), map()) :: tuple() def send_activity(conversation_id, activity) do url = "https://directline.botframework.com/v3/directline/conversations/#{conversation_id}/activities" headers = Util.generate_directline_header() modified_activity = Util.modify_activity(activity, nil) case HTTPoison.post(url, modified_activity, headers) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> id = body |> Poison.decode!() |> Map.get("id") {:ok, id} {:ok, _} -> {:error, "Error Sending Activity"} {:error, %HTTPoison.Error{reason: reason}} -> {:error, reason} end end @doc """ Receive the activities from a conversation. Parameters: * conversation_id - The Conversation ID * activity_id - The Activity ID we want reponse to Returns a Response object. """ @spec receive_activities(String.t(), String.t()) :: tuple() def receive_activities(conversation_id, activity_id) do url = "https://directline.botframework.com/v3/directline/conversations/#{conversation_id}/activities" headers = Util.generate_directline_header() case HTTPoison.get(url, headers) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> body |> Poison.decode!() |> Map.get("activities") |> Enum.filter(fn activity -> Map.get(activity, "replyToId") == activity_id end) {:ok, _} -> {:error, "Error Receiving Activities"} {:error, %HTTPoison.Error{reason: reason}} -> {:error, reason} end end @doc """ Send an activity to Directline the response is the Directline reponse. Parameters: * activity - The activity to send Returns a Directline Response """ @spec message(map()) :: map() def message(activity) do timeout = Config.get_request_timeout() with {:ok, conversation_id} <- Task.await( Task.async(fn -> start_conversation() end), timeout ), {:ok, activity_response} <- message_conversation(conversation_id, activity) do activity_response end end @doc """ Send an activity to a conversation the response is the Directline reponse. Parameters: * conversation_id - The conversation to send the activity * activity - The activity to send Returns a Directline Response """ @spec message_conversation(String.t(), map()) :: tuple() def message_conversation(conversation_id, activity) do timeout = Config.get_request_timeout() with {:ok, activity_id} <- Task.await( Task.async(fn -> send_activity(conversation_id, activity) end), timeout ), {:ok, activity_response} <- Task.await( Task.async(fn -> receive_activities(conversation_id, activity_id) end), timeout ) do {:ok, activity_response} end end end