normalize update mechanisms.
parent
e62da92b84
commit
6bd143babc
|
@ -41,20 +41,7 @@ defmodule Farmbot.Configurator.Router do
|
|||
|
||||
# Arduino-FW or FBOS Upload form.
|
||||
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)
|
||||
conn |> send_resp(200, make_html("firmware_upload"))
|
||||
end
|
||||
|
||||
# REST API
|
||||
|
@ -271,7 +258,8 @@ defmodule Farmbot.Configurator.Router do
|
|||
|
||||
if target != "host" do
|
||||
defp handle_os(file, conn) do
|
||||
Logger.info "Firmware update"
|
||||
Logger.info "Firmware update from network."
|
||||
Farmbot.System.Updates.setup_post_update()
|
||||
case Nerves.Firmware.upgrade_and_finalize(file) do
|
||||
{:error, reason} -> conn |> send_resp(400, inspect(reason))
|
||||
:ok ->
|
||||
|
|
|
@ -101,13 +101,22 @@ defmodule Farmbot.System.Updates do
|
|||
Logger.info "Found file: #{inspect file}", type: :success
|
||||
e -> Logger.error "Could not find update file: #{inspect e}"
|
||||
end
|
||||
|
||||
setup_post_update()
|
||||
|
||||
mod(@target).install(path)
|
||||
Farmbot.System.reboot()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Will cause `post_install/0` to be called next reboot.
|
||||
"""
|
||||
def setup_post_update() do
|
||||
FS.transaction fn ->
|
||||
Logger.info "Seting up post update!", type: :busy
|
||||
path = "#{FS.path()}/.post_update"
|
||||
:ok = File.write(path, "DONT CAT ME\r\n")
|
||||
end
|
||||
mod(@target).install(path)
|
||||
Farmbot.System.reboot()
|
||||
end, true
|
||||
end
|
||||
|
||||
@spec post_install :: no_return
|
||||
|
|
|
@ -1,39 +1,103 @@
|
|||
if Code.ensure_loaded?(Mix.Tasks.Firmware.Push) do
|
||||
defmodule Mix.Tasks.Farmbot.Upload do
|
||||
@moduledoc false
|
||||
use Mix.Task
|
||||
require IEx
|
||||
|
||||
defmodule Mix.Tasks.Farmbot.Upload do
|
||||
@moduledoc false
|
||||
use Mix.Task
|
||||
alias Mix.Tasks.Firmware.Push
|
||||
@shortdoc "Uploads a file to a url"
|
||||
def run([ipaddr | rest]) do
|
||||
otp_app = Mix.Project.config[:app]
|
||||
target = Mix.Project.config[:target]
|
||||
fw_file = if Enum.find(rest, fn(flag) ->
|
||||
flag == "--signed"
|
||||
end) do
|
||||
path = Path.join(["images", "#{Mix.env()}", "#{target}", "#{otp_app}-signed.fw"])
|
||||
Mix.shell.info "Using signed image: #{path}"
|
||||
path
|
||||
else
|
||||
path = Path.join(["images", "#{Mix.env()}", "#{target}", "#{otp_app}.fw"])
|
||||
Mix.shell.info "Using unsigned image: #{path}"
|
||||
path
|
||||
end
|
||||
Push.run([ipaddr, "--firmware", "#{fw_file}", "--reboot", "true"])
|
||||
@shortdoc "Uploads a file to a url"
|
||||
|
||||
def run(opts) do
|
||||
otp_app = Mix.Project.config[:app]
|
||||
target = Mix.Project.config[:target]
|
||||
|
||||
{keywords, [ip_address], _} =
|
||||
opts |> OptionParser.parse(switches: [signed: :boolean])
|
||||
|
||||
signed_bool = Keyword.get(keywords, :signed, false)
|
||||
file_name = Path.join(["images", "#{Mix.env()}", "#{target}", find_file_name(otp_app, signed_bool)])
|
||||
unless File.exists?(file_name) do
|
||||
Mix.raise("Could not find firmware: #{file_name}")
|
||||
end
|
||||
Mix.shell.info "Uploading firmware: #{file_name}"
|
||||
|
||||
start_httpc()
|
||||
http_opts = [relaxed: true, autoredirect: true]
|
||||
opts = []
|
||||
|
||||
{:ok, file} = :file.read_file('#{file_name}')
|
||||
file = :binary.bin_to_list(file)
|
||||
url = 'http://#{ip_address}/api/upload_firmware'
|
||||
boundary = '------------a450glvjfEoqerAc1p431paQlfDac152cadADfd'
|
||||
content_type = :lists.concat(['multipart/form-data; boundary=', boundary])
|
||||
body = format_multipart_formdata(boundary, [], [{:firmware, 'firmware.fw', file}])
|
||||
headers = [{'Content-Length', :erlang.integer_to_list(:erlang.length(body))}]
|
||||
|
||||
Mix.shell.info "Starting FW upload."
|
||||
|
||||
:httpc.request(:post,
|
||||
{url, headers, content_type, body},
|
||||
http_opts, opts)
|
||||
|> response
|
||||
end
|
||||
|
||||
else
|
||||
defp start_httpc() do
|
||||
Application.ensure_started(:inets)
|
||||
Application.ensure_started(:ssl)
|
||||
:inets.start(:httpc, profile: :farmbot_firmware)
|
||||
|
||||
defmodule Mix.Tasks.Farmbot.Upload do
|
||||
@moduledoc false
|
||||
use Mix.Task
|
||||
@shortdoc "Uploads a file to a url"
|
||||
def run(_) do
|
||||
Mix.raise """
|
||||
Something in your environment is borked!
|
||||
"""
|
||||
end
|
||||
opts = [
|
||||
max_sessions: 8,
|
||||
max_keep_alive_length: 4,
|
||||
max_pipeline_length: 4,
|
||||
keep_alive_timeout: 120_000,
|
||||
pipeline_timeout: 60_000
|
||||
]
|
||||
:httpc.set_options(opts, :farmbot_firmware)
|
||||
end
|
||||
|
||||
def response({:ok, {{_, 200, _}, _, _}}) do
|
||||
Mix.shell.info "Done"
|
||||
end
|
||||
|
||||
def response({:ok, {{_, status_code, _}, _, error}}) do
|
||||
Mix.shell.info "\nThere was an error applying the firmware: #{inspect status_code} #{inspect error}"
|
||||
end
|
||||
|
||||
def response({:error, error}) do
|
||||
Mix.shell.info "\nThere was an error applying the firmware: #{inspect error}"
|
||||
end
|
||||
|
||||
defp find_file_name(otp_app, true), do: "#{otp_app}-signed.fw"
|
||||
defp find_file_name(otp_app, false), do: "#{otp_app}.fw"
|
||||
|
||||
# i stole this from: https://gist.github.com/ArthurClemens/dbd70f9b7a4342810d923670a9db0f39
|
||||
defp format_multipart_formdata(boundary, fields, files) do
|
||||
field_parts = :lists.map(fn({field_name, field_content}) ->
|
||||
[:lists.concat(['--', boundary]),
|
||||
:lists.concat(['Content-Disposition: form-data; name=\"',
|
||||
:erlang.atom_to_list(field_name), '\"']),
|
||||
'',
|
||||
field_content]
|
||||
end, fields)
|
||||
|
||||
field_parts_2 = :lists.append(field_parts)
|
||||
|
||||
file_parts = :lists.map(fn({field_name, file_name, file_content}) ->
|
||||
[
|
||||
:lists.concat(['--', boundary]),
|
||||
:lists.concat(['Content-Disposition: format-data; name=\"',
|
||||
:erlang.atom_to_list(field_name),
|
||||
'\"; filename=\"', file_name, '\"']),
|
||||
:lists.concat(['Content-Type: ', 'application/octet-stream']),
|
||||
'',
|
||||
file_content
|
||||
]
|
||||
end, files)
|
||||
|
||||
file_parts_2 = :lists.append(file_parts)
|
||||
|
||||
ending_parts = [:lists.concat(['--', boundary, '--']), '']
|
||||
parts = :lists.append([field_parts_2, file_parts_2, ending_parts])
|
||||
:string.join(parts, '\r\n')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
4
mix.exs
4
mix.exs
|
@ -99,7 +99,7 @@ defmodule Farmbot.Mixfile do
|
|||
defp target_applications("host"), do: []
|
||||
defp target_applications(_system), do: [
|
||||
:nerves_interim_wifi,
|
||||
:nerves_firmware_http,
|
||||
# :nerves_firmware_http,
|
||||
:nerves_firmware,
|
||||
:nerves_ssdp_server
|
||||
]
|
||||
|
@ -221,7 +221,7 @@ defmodule Farmbot.Mixfile do
|
|||
# {:nerves_interim_wifi, path: "../nerves_interim_wifi"},
|
||||
{:nerves_interim_wifi, github: "nerves-project/nerves_interim_wifi"},
|
||||
|
||||
{:nerves_firmware_http, "~> 0.3.1"},
|
||||
# {:nerves_firmware_http, "~> 0.3.1"},
|
||||
|
||||
# {:nerves_firmware, "~> 0.3"},
|
||||
# {:nerves_firmware, path: "../nerves_firmware", override: true},
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
*
|
||||
!index.html
|
||||
!.gitignore
|
||||
!easter_eggs.json
|
||||
!farmbot_logo.png
|
||||
!firmware_shell.html
|
||||
!log.html
|
||||
!*.html
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<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>
|
Loading…
Reference in New Issue