pull/335/head
Connor Rigby 2017-07-09 20:04:09 -07:00
parent 75fd7c186d
commit ef8e2a819f
8 changed files with 73 additions and 46 deletions

View File

@ -9,7 +9,7 @@ defmodule Farmbot.CeleryScript.Ast do
defimpl Inspect, for: __MODULE__ do
def inspect(thing, _) do
"#CeleryScript<#{thing.kind}: [:#{Enum.join(Map.keys(thing.args), ", :")}]>"
"#CeleryScript<#{thing.kind}: #{Map.keys(thing.args)}>"
end
end

View File

@ -97,9 +97,9 @@ defmodule Farmbot.Context do
http: http,
transport: transport,
farmware_manager: farmware_manager,
ref: reference,
regimen_supervisor: regimen_supervisor,
data_stack: [Ast.t]
ref: reference,
data_stack: [Ast.t]
}
@spec push_data(t, Ast.t) :: t

View File

@ -3,27 +3,53 @@ defmodule Farmbot.Farmware.HTTPServer do
alias Farmbot.Farmware.JWT
use Plug.Router
@max_length 111_409_842
plug Plug.Parsers, parsers:
[:urlencoded, :multipart, :json], json_decoder: Poison, length: @max_length
plug :match
plug :dispatch
def start_link(%Context{} = context, %JWT{} = token) do
Plug.Adapters.Cowboy.http __MODULE__, [jwt: token], [port: 8081]
def start_link(%Context{} = context, %JWT{} = token, port) do
Plug.Adapters.Cowboy.http __MODULE__, [jwt: token, context: context], [port: port]
end
def init(opts), do: opts
def call(conn, opts) do
jwt = Keyword.fetch!(opts, :jwt)
ctx = Keyword.fetch!(opts, :context)
jwt_enc = jwt |> Poison.encode!() |> :base64.encode()
case conn |> get_req_header("authorization") do
["bearer " <> ^jwt_enc] -> send_resp(conn, 200, "ok")
[^jwt_enc] -> send_resp(conn, 200, "ok")
_ -> send_resp(conn, 422, "Bad token")
["bearer " <> ^jwt_enc] -> handle(conn, conn.method, conn.request_path, ctx)
_ -> send_resp(conn, 422, "Bad token")
end
end
match _, do: send_resp(conn, 500, "wuh oh")
defp handle(conn, "GET", "/", _ctx) do
send_resp(conn, 200, "<html> <head> </head> <body> ... </body> </html>")
end
defp handle(conn, "GET", "/status", ctx) do
ctx
|> Farmbot.Transport.force_state_push()
|> Poison.encode!
|> fn(state) -> conn
|> put_resp_header("content-type", "application/json")
|> send_resp(200, state)
end.()
end
defp handle(conn, "POST", "/celery_script", ctx) do
try do
{:ok, body, conn} = conn |> read_body()
ast = body |> Poison.decode! |> Farmbot.CeleryScript.Ast.parse()
_new_ctx = Farmbot.CeleryScript.Command.do_command(ast, ctx)
conn
|> put_resp_header("location", "/status")
|> send_resp(302, "redirect")
rescue
e in Farmbot.CeleryScript.Error -> conn |> send_resp(500, "CeleryScript error: #{e.message}")
e in Poison.SyntaxError -> conn |> send_resp(500, "JSON Parse error: #{e.message}")
e -> conn |> send_resp(500, "Unknown Error: #{inspect e}")
end
end
match _ , do: send_resp(conn, 500, "Unknown Error.")
end

View File

@ -181,8 +181,8 @@ defmodule Farmbot.Farmware.Installer do
end
end
def path, do: "#{FS.path()}/farmware"
def repo_path, do: "#{path()}/repos"
def path, do: "#{FS.path()}/farmware"
def repo_path, do: "#{path()}/repos"
def package_path, do: "#{path()}/packages"
defp unzip!(zip_file, path) when is_bitstring(zip_file) do

View File

@ -31,7 +31,7 @@ defmodule Farmbot.Farmware.Manager do
"""
@spec lookup(Context.t, uuid) :: {:ok, Farmware.t} | {:error, term}
def lookup(%Context{farmware_manager: fwt}, uuid) do
GenServer.call(fwt, {:lookup, uuid})
GenServer.call(fwt, {:lookup, uuid})
end
@doc """
@ -122,8 +122,8 @@ defmodule Farmbot.Farmware.Manager do
def init(ctx) do
state = %State{
context: ctx,
farmwares: %{}
context: ctx,
farmwares: %{},
}
dispatch nil, state
{:ok, state}

View File

@ -27,6 +27,24 @@ defmodule Farmbot.Farmware.Runtime do
@clean_up_timeout 30_000
#this is so stupid
defp lookup_port do
path = "#{Farmbot.System.FS.path()}/farmware/port"
last = case File.read(path) do
{:error, :enoent} -> 8000
str -> str |> String.trim() |> String.to_integer()
end
if last > 8099 do
File.write!(path, "#{8000}")
8000
else
File.write!(path, "#{last + 1}")
last + 1
end
end
@doc """
Executes a Farmware inside a safe sandbox
"""
@ -36,10 +54,11 @@ defmodule Farmbot.Farmware.Runtime do
Process.flag(:trap_exit, true)
uuid = Nerves.Lib.UUID.generate()
fw_jwt = %Farmware.JWT{start_time: Timex.now() |> DateTime.to_iso8601()}
env = environment(ctx, fw_jwt)
port = lookup_port()
env = environment(ctx, fw_jwt, port)
exec = lookup_exec_or_raise(fw.executable, fw.path)
cwd = File.cwd!
{:ok, server} = Farmware.HTTPServer.start_link(fw_jwt)
{:ok, server} = Farmware.HTTPServer.start_link(ctx, fw_jwt, port)
case File.cd(fw.path) do
:ok -> :ok
@ -116,25 +135,6 @@ defmodule Farmbot.Farmware.Runtime do
end
end
@spec handle_script_output(state, binary) :: Context.t | no_return
defp handle_script_output(%State{} = state, data) do
<<uuid :: size(288) >> = state.uuid
case data do
<< ^uuid :: size(288), json :: binary >> ->
debug_log "going to try to do: #{json}"
new_context =
json
|> String.trim()
|> Poison.decode!()
|> CeleryScript.Ast.parse()
|> CeleryScript.Command.do_command(state.context)
%{state | context: new_context}
_data ->
Logger.info("[#{state.farmware.name}] Sent data: #{data}")
%{state | output: [data | state.output]}
end
end
@spec maybe_kill_port(port) :: :ok
defp maybe_kill_port(port) do
debug_log "trying to kill port: #{inspect port}"
@ -149,13 +149,14 @@ defmodule Farmbot.Farmware.Runtime do
end
end
defp environment(%Context{} = ctx, fw_jwt) do
defp environment(%Context{} = ctx, fw_jwt, port) do
fw_tkn_enc = fw_jwt |> Poison.encode! |> :base64.encode()
envs = BotState.get_user_env(ctx)
{:ok, %Farmbot.Token{} = tkn} = Auth.get_token(ctx.auth)
envs = envs
|> Map.put("API_TOKEN", tkn)
|> Map.put("API_TOKEN", tkn)
|> Map.put("FARMWARE_TOKEN", fw_tkn_enc)
|> Map.put("FARMWARE_URL", "http://localhost:#{port}/")
|> Map.put("IMAGES_DIR", "/tmp/images")
Enum.map(envs, fn({key, val}) -> {to_erl_safe(key), to_erl_safe(val)} end)
end

View File

@ -143,7 +143,7 @@ defmodule Farmbot.Mixfile do
{:exjsx, "~> 3.2", override: true},
{:rsa, "~> 0.0.1"},
{:httpoison, "~> 0.12"},
{:hackney, path: "../hackney", override: true},
# {:hackney, path: "../hackney", override: true},
# MQTT stuff
{:gen_mqtt, "~> 0.3.1"}, # for rpc transport

View File

@ -2,7 +2,7 @@
"bootloader": {:git, "https://github.com/nerves-project/bootloader.git", "c77b81c56689a8dbda2ce9f78f4432e3540a9b81", []},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"calendar": {:hex, :calendar, "0.17.1", "5c7dfffde2b68011c2d6832ff1a15496292de965a3b57b3fad32405f1176f024", [:mix], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"certifi": {:git, "https://github.com/certifi/erlang-certifi", "fc75f3357932d042b0306fc60ca1353cec2a4fa7", [tag: "1.2.1"]},
"certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], [], "hexpm"},
"combine": {:hex, :combine, "0.9.6", "8d1034a127d4cbf6924c8a5010d3534d958085575fa4d9b878f200d79ac78335", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cors_plug": {:hex, :cors_plug, "1.2.1", "bbe1381a52e4a16e609cf3c4cbfde6884726a58b9a1a205db104dbdfc542f447", [:mix], [{:plug, "> 0.8.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
@ -32,12 +32,12 @@
"hackney": {:hex, :hackney, "1.8.6", "21a725db3569b3fb11a6af17d5c5f654052ce9624219f1317e8639183de4a423", [:rebar3], [{:certifi, "1.2.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.0.2", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "0.12.0", "8fc3d791c5afe6beb0093680c667dd4ce712a49d89c38c3fe1a43100dd76cf90", [:mix], [{:hackney, "~> 1.8.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"ibrowse": {:hex, :ibrowse, "4.2.2", "b32b5bafcc77b7277eff030ed32e1acc3f610c64e9f6aea19822abcadf681b4b", [:rebar3], []},
"idna": {:git, "https://github.com/benoitc/erlang-idna", "58f09dcd44faf3c685c350cf72bde1e85fc5895d", [tag: "5.0.2"]},
"idna": {:hex, :idna, "5.0.2", "ac203208ada855d95dc591a764b6e87259cb0e2a364218f215ad662daa8cd6b4", [:rebar3], [{:unicode_util_compat, "0.2.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], [], "hexpm"},
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:make, :rebar], [], "hexpm"},
"metrics": {:git, "https://github.com/benoitc/erlang-metrics", "c6eb4dcf29f9e907539915e2ab996f40c2ec7e8e", [tag: "1.0.1"]},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [:mix], [], "hexpm"},
"mimerl": {:git, "https://github.com/benoitc/mimerl", "678aba028a690da6822c87410d475841c048b6bf", [tag: "1.0.2"]},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.2.1", "bfdba786903e77f9c18772dee472d020ceb8ef000783e737725a4c8f54ad28ec", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mustache": {:hex, :mustache, "0.0.2", "870fbef411c47d17df06a57b8b3f69e26eb110cba0177c34e273db5d94369d9b", [:mix], [], "hexpm"},
"nerves": {:hex, :nerves, "0.5.1", "a55d73752e8f271c7aca5fbe47747f07d0e7760b5e858e7f8da17ab06287f49c", [:mix], [{:distillery, "~> 1.0", [hex: :distillery, repo: "hexpm", optional: false]}], "hexpm"},
@ -63,7 +63,7 @@
"redix": {:hex, :redix, "0.5.1", "2bf874a186cc759791b8defdd0bfaa752784716bd48241f6aa972a20e7f95745", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
"rollbax": {:hex, :rollbax, "0.8.2", "204a47a83fe32745def19ea0307b297395c00315fb85f30dfda04d5009b5ecb9", [:mix], [{:hackney, "~> 1.1", [hex: :hackney, repo: "hexpm", optional: false]}, {:poison, "~> 1.4 or ~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"rsa": {:hex, :rsa, "0.0.1", "a63069f88ce342ffdf8448b7cdef4b39ba7dee3c1510644a39385c7e63ba246f", [:mix], [], "hexpm"},
"ssl_verify_fun": {:git, "https://github.com/deadtrickster/ssl_verify_fun.erl", "33406f6decdcb9f03cf1e69e34728a288af156a0", [tag: "1.1.1"]},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
"syslog": {:hex, :syslog, "1.0.2", "9cf72c0986675a170c03b210e49700845a0f7b61e96d302a3ba0df82963daf60", [:rebar], [], "hexpm"},
"system_registry": {:hex, :system_registry, "0.1.2", "b6dba36c575786f1848e18a1155a2b6bd82f607f0ae9dc88185d6b7dc3fcdf60", [:mix], []},
"timex": {:hex, :timex, "3.1.7", "71f9c32e13ff4860e86a314303757cc02b3ead5db6e977579a2935225ce9a666", [:mix], [{:combine, "~> 0.7", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},