farmbot_os/lib/farmbot/http.ex

114 lines
3.2 KiB
Elixir

defmodule Farmbot.HTTP do
@moduledoc """
Shortcuts to Http Client because im Lazy.
"""
alias Farmbot.Auth
alias Farmbot.Token
use HTTPoison.Base
require Logger
alias Farmbot.CeleryScript.Ast.Context
@version Mix.Project.config[:version]
@target Mix.Project.config[:target]
@twenty_five_seconds 25_000
@http_config [
ssl: [versions: [:'tlsv1.2']],
recv_timeout: @twenty_five_seconds,
timeout: @twenty_five_seconds,
follow_redirect: true
]
@type http_resp :: HTTPoison.Response.t | {:error, HTTPoison.ErrorResponse.t}
defp context, do: Context.new()
def process_url(url) do
{:ok, server} = fetch_server(context().auth)
server <> url
end
def process_request_headers(_headers) do
{:ok, auth_headers} = build_auth(context())
auth_headers
end
def process_request_options(opts),
do: opts
|> Keyword.merge(@http_config, fn(_key, user_provided, _default) ->
user_provided
end)
def process_status_code(401) do
Logger.info ">> Token is expired!"
Farmbot.Auth.try_log_in!(context().auth)
401
end
def process_status_code(code), do: code
@spec build_auth(Context.t) :: {:ok, [any]} | {:error, :no_token}
defp build_auth(%Context{} = context) do
with {:ok, %Token{} = token} <- Auth.get_token(context.auth)
do
{:ok,
["Content-Type": "application/json",
"User-Agent": "FarmbotOS/#{@version} (#{@target}) #{@target} ()",
"Authorization": "Bearer " <> token.encoded]}
else
_ -> {:error, :no_token}
end
end
@spec fetch_server(Context.auth) :: {:error, :no_server} | {:ok, binary}
defp fetch_server(auth) do
case Auth.get_server(auth) do
{:ok, nil} -> {:error, :no_server}
{:ok, server} -> {:ok, server}
end
end
@doc """
Uploads a file to google storage
"""
@spec upload_file(binary) :: {:ok, HTTPoison.Response.t} | no_return
def upload_file(file_name) do
unless File.exists?(file_name) do
raise("File not found")
end
{:ok, %HTTPoison.Response{body: rbody,
status_code: 200}} = get("/api/storage_auth")
{:ok, file} = File.read(file_name)
body = Poison.decode!(rbody)
url = "https:" <> body["url"]
form_data = body["form_data"]
attachment_url = url <> form_data["key"]
headers = [
{"Content-Type", "multipart/form-data"},
{"User-Agent", "FarmbotOS"}
]
payload =
Enum.map(form_data, fn({key, value}) ->
if key == "file", do: {"file", file}, else: {key, value}
end)
Logger.info ">> #{attachment_url} Should hopefully exist shortly!"
url
|> HTTPoison.post({:multipart, payload}, headers)
|> finish_upload(attachment_url)
end
@spec finish_upload(any, binary) :: {:ok, HTTPoison.Response.t} | no_return
# We only want to upload if we get a 2XX response.
defp finish_upload({:ok, %HTTPoison.Response{status_code: s}}, attachment_url)
when s < 300 do
context = Context.new()
[x, y, z] = Farmbot.BotState.get_current_pos(context)
meta = %{x: x, y: y, z: z}
json = Poison.encode! %{"attachment_url" => attachment_url,
"meta" => meta}
Farmbot.HTTP.post "/api/images", json
end
end