241 lines
6.4 KiB
Elixir
241 lines
6.4 KiB
Elixir
defmodule Farmbot.Configurator.Router do
|
|
@moduledoc """
|
|
Routes incoming connections.
|
|
"""
|
|
alias Farmbot.System.FS.ConfigStorage
|
|
alias Farmbot.System.Network, as: NetMan
|
|
require Logger
|
|
|
|
use Plug.Router
|
|
plug Plug.Logger
|
|
# this is so we can serve the bundle.js file.
|
|
plug Plug.Static, at: "/", from: :farmbot
|
|
plug Plug.Static, at: "/image", from: "/tmp/images", gzip: false
|
|
|
|
plug Plug.Parsers, parsers: [:urlencoded, :json],
|
|
pass: ["*/*"],
|
|
json_decoder: Poison
|
|
plug :match
|
|
plug :dispatch
|
|
plug CORSPlug
|
|
|
|
target = Mix.Project.config[:target]
|
|
|
|
if Mix.env == :dev, do: use Plug.Debugger, otp_app: :farmbot
|
|
|
|
get "/image/latest" do
|
|
list_images = fn() ->
|
|
"/tmp/images"
|
|
|> File.ls!
|
|
|> Enum.reduce("", fn(image, acc) ->
|
|
acc <> "<img src=\"/image/#{image}\">"
|
|
end)
|
|
end
|
|
html =
|
|
~s"""
|
|
<html>
|
|
<body>
|
|
<form action=/image/capture>
|
|
<input type="submit" value="Capture">
|
|
</form>
|
|
#{list_images.()}
|
|
</body>
|
|
</html>
|
|
"""
|
|
conn |> send_resp(200, html)
|
|
end
|
|
|
|
get "/image/capture" do
|
|
Farmbot.Camera.capture()
|
|
conn
|
|
|> put_resp_header("location", "/image/latest")
|
|
|> send_resp(302, "OK")
|
|
end
|
|
|
|
get "/", do: conn |> send_resp(200, make_html())
|
|
get "/setup" do
|
|
conn
|
|
|> put_resp_header("location", "http://192.168.24.1/index.html")
|
|
|> send_resp(302, "OK")
|
|
end
|
|
|
|
get "/api/config" do
|
|
# Already in json form.
|
|
{:ok, config} = ConfigStorage.read_config_file
|
|
conn |> send_resp(200, config)
|
|
end
|
|
|
|
post "/api/config" do
|
|
Logger.info ">> router got config json"
|
|
{:ok, _body, conn} = read_body(conn)
|
|
ConfigStorage.replace_config_file(conn.body_params)
|
|
conn |> send_resp(200, "OK")
|
|
end
|
|
|
|
post "/api/config/creds" do
|
|
Logger.info ">> router got credentials"
|
|
{:ok, _body, conn} = read_body(conn)
|
|
|
|
%{"email" => email,"pass" => pass,"server" => server} = conn.body_params
|
|
Farmbot.Auth.interim(email, pass, server)
|
|
conn |> send_resp(200, "OK")
|
|
end
|
|
|
|
post "/api/network/scan" do
|
|
{:ok, _body, conn} = read_body(conn)
|
|
%{"iface" => iface} = conn.body_params
|
|
scan = NetMan.scan(iface)
|
|
case scan do
|
|
{:error, reason} -> conn |> send_resp(500, "could not scan: #{inspect reason}")
|
|
ssids -> conn |> send_resp(200, Poison.encode!(ssids))
|
|
end
|
|
end
|
|
|
|
get "/api/network/interfaces" do
|
|
blah = Farmbot.System.Network.enumerate
|
|
case Poison.encode(blah) do
|
|
{:ok, interfaces} ->
|
|
conn |> send_resp(200, interfaces)
|
|
{:error, reason} ->
|
|
conn |> send_resp(500, "could not enumerate interfaces: #{inspect reason}")
|
|
error ->
|
|
conn |> send_resp(500, "could not enumerate interfaces: #{inspect error}")
|
|
end
|
|
end
|
|
|
|
post "/api/factory_reset" do
|
|
Logger.info "goodbye."
|
|
spawn fn() ->
|
|
# sleep to allow the request to finish.
|
|
Process.sleep(100)
|
|
Farmbot.System.factory_reset
|
|
end
|
|
conn |> send_resp(204, "GoodByeWorld!")
|
|
end
|
|
|
|
post "/api/try_log_in" do
|
|
Logger.info "Trying to log in. "
|
|
spawn fn() ->
|
|
# sleep to allow the request to finish.
|
|
Process.sleep(100)
|
|
|
|
# restart network.
|
|
# not going to bother checking if it worked or not, (at least until i
|
|
# reimplement networking) because its so fragile.
|
|
Farmbot.System.Network.restart
|
|
end
|
|
conn |> send_resp(200, "OK")
|
|
end
|
|
|
|
get "/api/logs" do
|
|
logs = GenEvent.call(Logger, Farmbot.Logger, :messages)
|
|
|
|
only_messages = Enum.map(logs, fn(log) ->
|
|
log.message
|
|
end)
|
|
json = Poison.encode!(only_messages)
|
|
conn |> send_resp(200, json)
|
|
end
|
|
|
|
get "/api/state" do
|
|
Farmbot.BotState.Monitor.get_state
|
|
state = Farmbot.Transport.get_state
|
|
json = Poison.encode!(state)
|
|
conn |> send_resp(200, json)
|
|
end
|
|
|
|
post "/api/flash_firmware" do
|
|
"#{:code.priv_dir(:farmbot)}/firmware.hex" |> handle_arduino(conn)
|
|
end
|
|
|
|
get "/firmware/upload" do
|
|
html = ~s"""
|
|
<html>
|
|
<body>
|
|
<p>
|
|
Upload a FarmbotOS Firmware file (.fw) or a Arduino Firmware file (.hex)
|
|
</p>
|
|
<form action="/api/upload_firmware" method="post" enctype="multipart/form-data" accept="*">
|
|
<input type="file" name="firmware" id="fileupload">
|
|
<input type="submit" value="submit">
|
|
</form>
|
|
</body>
|
|
</html>
|
|
"""
|
|
conn |> send_resp(200, html)
|
|
end
|
|
|
|
plug Plug.Parsers, parsers: [:urlencoded, :multipart], length: 111409842
|
|
post "/api/upload_firmware" do
|
|
{:ok, _body, conn} = Plug.Conn.read_body(conn)
|
|
upload = conn.body_params["firmware"]
|
|
file = upload.path
|
|
case Path.extname(upload.filename) do
|
|
".hex" ->
|
|
Logger.info "FLASHING ARDUINO!"
|
|
handle_arduino(file, conn)
|
|
".fw" ->
|
|
Logger.info "FLASHING OS"
|
|
handle_os(file, conn)
|
|
_ ->
|
|
conn |> send_resp(400, "COULD NOT HANDLE #{upload.filename}")
|
|
end
|
|
end
|
|
|
|
# anything that doesn't match a rest end point gets the index.
|
|
match _, do: conn |> send_resp(404, "not found")
|
|
|
|
@spec make_html :: binary
|
|
defp make_html do
|
|
"#{:code.priv_dir(:farmbot)}/static/index.html" |> File.read!
|
|
end
|
|
|
|
defp handle_arduino(file, conn) do
|
|
errrm = fn(blerp) ->
|
|
receive do
|
|
:done ->
|
|
blerp |> send_resp(200, "OK")
|
|
{:error, reason} ->
|
|
blerp |> send_resp(400, IO.inspect(reason))
|
|
end
|
|
end
|
|
|
|
Logger.info ">> is installing a firmware update. "
|
|
<> " I may act weird for a moment", channels: [:toast]
|
|
|
|
if Farmbot.Serial.Handler.available? do
|
|
GenServer.cast(Farmbot.Serial.Handler, {:update_fw, file, self()})
|
|
errrm.(conn)
|
|
else
|
|
Logger.debug "doing some magic..."
|
|
herp = Nerves.UART.enumerate()
|
|
|> Map.drop(["ttyS0","ttyAMA0"])
|
|
|> Map.keys
|
|
case herp do
|
|
[tty] ->
|
|
Logger.debug "magic complete!"
|
|
Farmbot.Serial.Handler.flash_firmware(tty, file, self())
|
|
errrm.(conn)
|
|
_ ->
|
|
Logger.warn "Please only have one serial device when updating firmware"
|
|
conn |> send_resp(200, "OK")
|
|
end
|
|
end
|
|
end
|
|
|
|
if target != "host" do
|
|
defp handle_os(file, conn) do
|
|
Logger.info "Firmware update"
|
|
case Nerves.Firmware.upgrade_and_finalize(file) do
|
|
{:error, reason} -> conn |> send_resp(400, inspect(reason))
|
|
:ok ->
|
|
conn |> send_resp(200, "UPGRADING")
|
|
Process.sleep(2000)
|
|
Nerves.Firmware.reboot
|
|
end
|
|
end
|
|
else
|
|
defp handle_os(_file, conn), do: conn |> send_resp(200, "OK")
|
|
end
|
|
end
|