Current section
Files
Jump to
Current section
Files
lib/receive/poller.ex
defmodule Agala.Provider.Vk.Poller do
@moduledoc """
### How poller works?
Poller gets all needed options in `start_link/1` argument. In these options `:chain`
is specified.
So the Poller make periodical work:
1. HTTP get new updates from Telegram server
2. Split this array into separate event
3. Handle particular each event with chain
4. Restart cycle again
"""
use Agala.Bot.Common.Poller
alias Agala.BotParams
#######################################################################################
### Initialize section
#######################################################################################
@spec bootstrap(Agala.BotParams.t()) :: {:ok, Agala.BotParams}
defdelegate bootstrap(bot_params), to: Agala.Provider.Vk.Poller.Bootstrap
#######################################################################################
### Get updates section
#######################################################################################
@vsn 2
defp get_updates_url(%BotParams{private: %{
key: key,
mode: mode,
server: server,
ts: ts,
wait: wait
}}) do
"https://"<>server<>
"?act=a_check&key="<>key<>
"&ts="<>Integer.to_string(ts)<>
"&wait="<>Integer.to_string(wait)<>
"&mode="<>Integer.to_string(mode)<>
"&version"<>Integer.to_string(@vsn)
end
defp get_updates_options(%BotParams{private: %{http_opts: http_opts}}), do: http_opts
defp parse_body({:ok, resp = %HTTPoison.Response{body: body}}) do
{:ok, %HTTPoison.Response{resp | body: Poison.decode!(body)}}
end
defp parse_body(default), do: default
def get_updates(bot_params = %BotParams{}) do
HTTPoison.get(
get_updates_url(bot_params), # url
[{"Content-Type", "application/json"}], # headers
get_updates_options(bot_params) # opts
)
|> parse_body()
|> resolve_updates(bot_params)
end
######################################################################################
### Known errors
######################################################################################
### Corrupted history
defp resolve_updates(
{
:ok,
%HTTPoison.Response{
status_code: _,
body: %{"ts" => ts, "failed" => 1}
}
},
bot_params
) do
Logger.debug "Event history is corrupted, resending with new timestamp..."
Agala.set(bot_params, :poll_server_ts, ts)
{[], bot_params |> put_in([:private, :ts], ts)}
end
### Key is expired
defp resolve_updates(
{
:ok,
%HTTPoison.Response{
status_code: _,
body: %{"failed" => 2}
}
},
bot_params
) do
Logger.debug "Key's active period expired. Retrieving new key..."
{[], bot_params |> put_in([:common, :restart], true)}
end
### User information is lost
defp resolve_updates(
{
:ok,
%HTTPoison.Response{
status_code: _,
body: %{"failed" => 3}
}
},
bot_params
) do
Logger.debug "User information was lost. Retrieving new key and timestamp..."
{[], bot_params |> put_in([:common, :restart], true)}
end
### Version invalid
defp resolve_updates(
{
:ok,
%HTTPoison.Response{
status_code: _,
body: %{"failed" => 4}
}
},
bot_params
) do
Logger.debug "Invalid version number was passed. Restarting..."
{[], bot_params |> put_in([:common, :restart], true)}
end
### -----------------------------------------------------------------------------
defp resolve_updates(
{
:ok,
%HTTPoison.Response{
status_code: 200,
body: %{"ts" => ts, "updates" => []}
}
},
bot_params
) do
# We are seting ts to the safe place in order to get if this poller will
# be restarted
Agala.set(bot_params, :poll_server_ts, ts)
{[], bot_params |> put_in([:private, :ts], ts)}
end
defp resolve_updates(
{
:error,
%HTTPoison.Error{
id: nil,
reason: :timeout
}
},
bot_params
) do
# This is just failed long polling, simply restart
Logger.debug("Long polling request ended with timeout, resend to poll")
{[], bot_params}
end
defp resolve_updates(
{
:ok,
%HTTPoison.Response{
status_code: 200,
body: %{"ts" => ts, "updates" => updates}
}
},
bot_params
) do
Logger.debug fn -> "Response body is:\n #{inspect updates}" end
Agala.set(bot_params, :poll_server_ts, ts)
{updates, bot_params |> put_in([:private, :ts], ts)}
end
defp resolve_updates({:ok, %HTTPoison.Response{status_code: status_code, body: body}}, _, bot_params) do
Logger.warn("HTTP response ended with status code #{inspect status_code}\nand body:\n#{inspect body}")
{[], bot_params}
end
defp resolve_updates({:error, err}, _, bot_params) do
Logger.warn("#{inspect err}")
{[], bot_params}
end
end