making progress
parent
b6b3020702
commit
94e3a21970
|
@ -21,14 +21,15 @@ defmodule Farmbot.Bootstrap.Configurator do
|
|||
"""
|
||||
def start_link(_, opts) do
|
||||
Logger.info "Configuring Farmbot."
|
||||
case Supervisor.start_link(__MODULE__, [self()], opts) do
|
||||
{:ok, pid} ->
|
||||
receive do
|
||||
:ok -> stop(pid, :ignore)
|
||||
{:error, _reason} = err -> stop(pid, err)
|
||||
end
|
||||
:ignore -> :ignore
|
||||
end
|
||||
sup = Supervisor.start_link(__MODULE__, [self()], opts)
|
||||
# case supervisor do
|
||||
# {:ok, pid} ->
|
||||
# receive do
|
||||
# :ok -> stop(pid, :ignore)
|
||||
# {:error, _reason} = err -> stop(pid, err)
|
||||
# end
|
||||
# :ignore -> :ignore
|
||||
# end
|
||||
end
|
||||
|
||||
def init(cb) do
|
||||
|
|
|
@ -9,7 +9,7 @@ defmodule Farmbot.Bootstrap.Configurator.HTML do
|
|||
end
|
||||
|
||||
@doc "Render a page in the `priv/templates/page` dir."
|
||||
def render(page) do
|
||||
eval_file("page", [page: page, render: fn -> eval_file("page/#{page}") end])
|
||||
def render(page, conn \\ %{}) do
|
||||
eval_file("page", [page: page, conn: conn, render: fn -> eval_file("page/#{page}") end])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,59 +3,101 @@ defmodule Farmbot.Bootstrap.Configurator.Router do
|
|||
|
||||
use Plug.Router
|
||||
|
||||
if Mix.env == :dev do
|
||||
use Plug.Debugger, otp_app: :farmbot
|
||||
end
|
||||
|
||||
plug Plug.Static, from: {:farmbot, "priv/static"}, at: "/"
|
||||
plug Plug.Session, store: :ets, key: "session", table: :session
|
||||
plug Plug.Session, store: :ets, key: "page", table: :session
|
||||
plug Plug.Session, store: :ets, key: "page_complete", table: :session
|
||||
plug Plug.Logger, log: :debug
|
||||
plug Plug.Parsers, parsers: [:urlencoded, :multipart]
|
||||
plug :match
|
||||
plug :dispatch
|
||||
|
||||
import Farmbot.Bootstrap.Configurator.HTML
|
||||
require Logger
|
||||
|
||||
get "/" do
|
||||
conn = conn |> fetch_session()
|
||||
# session = conn |> get_session("session")
|
||||
conn
|
||||
|> put_session("session", 0)
|
||||
|> send_resp(200, render("page0"))
|
||||
end
|
||||
|
||||
get "/previous" do
|
||||
conn = conn |> fetch_session()
|
||||
session = conn |> get_session("session")
|
||||
cond do
|
||||
is_nil(session) ->
|
||||
conn
|
||||
|> put_session("session", 0)
|
||||
|> send_resp(200, render("page0"))
|
||||
is_number(session) ->
|
||||
conn |> handle_step(session - 1)
|
||||
end
|
||||
|> fetch_session()
|
||||
# Reset the page session.
|
||||
|> put_session("page_complete", false)
|
||||
# Goto 0.
|
||||
|> handle_step(0)
|
||||
end
|
||||
|
||||
get "/next" do
|
||||
# Fetch sessions.
|
||||
conn = conn |> fetch_session()
|
||||
session = conn |> get_session("session")
|
||||
# get the current page.
|
||||
page = conn |> get_session("page")
|
||||
# check if the page is complete.
|
||||
comp = conn |> get_session("page_complete")
|
||||
# Set page complete to false for the next page.
|
||||
conn = conn |> put_session("page_complete", false)
|
||||
cond do
|
||||
is_nil(session) ->
|
||||
conn
|
||||
|> put_session("session", 0)
|
||||
|> send_resp(200, render("page0"))
|
||||
is_number(session) ->
|
||||
conn |> handle_step(session + 1)
|
||||
# if page is complete, and we are actually on a page go to the next page.
|
||||
(comp == true) and (is_number(page)) ->
|
||||
conn |> handle_step(page + 1)
|
||||
# if we aren't on a page, go back to index.
|
||||
is_nil(page) ->
|
||||
conn |> put_resp_header("location", "/") |> send_resp(302, "/")
|
||||
# Else, just refresh this page.
|
||||
true -> do_render(conn, page)
|
||||
end
|
||||
end
|
||||
|
||||
post "/next" do
|
||||
conn
|
||||
# Read and store this pages data.
|
||||
|> save_data
|
||||
# Set page to complete.
|
||||
|> put_session("page_complete", true)
|
||||
# GET the next page.
|
||||
|> put_resp_header("location", "/next")
|
||||
|> send_resp(302, "/next")
|
||||
end
|
||||
|
||||
post "/finish" do
|
||||
conn
|
||||
|> save_data()
|
||||
|> send_resp(200, "goodbye.")
|
||||
end
|
||||
|
||||
get "/flash_fw" do
|
||||
Process.sleep(5000)
|
||||
conn |> send_resp(200, "ok")
|
||||
end
|
||||
|
||||
get "/scan_wifi" do
|
||||
conn |> send_resp(200, Poison.encode!(["hello", "world"]))
|
||||
end
|
||||
|
||||
defp save_data(conn) do
|
||||
{:ok, _, conn} = conn |> fetch_session() |> read_body()
|
||||
IO.inspect conn.body_params
|
||||
conn
|
||||
end
|
||||
|
||||
defp handle_step(conn, num) do
|
||||
try do
|
||||
conn
|
||||
|> put_session("session", num)
|
||||
|> send_resp(200, render("page#{num}"))
|
||||
|> put_session("page", num)
|
||||
|> do_render(num)
|
||||
rescue
|
||||
_ ->
|
||||
Logger.warn "Resetting page."
|
||||
conn
|
||||
|> put_session("session", 0)
|
||||
|> send_resp(200, render("page0"))
|
||||
|> put_session("page", nil)
|
||||
|> put_resp_header("location", "/")
|
||||
|> send_resp(302, "/")
|
||||
end
|
||||
end
|
||||
|
||||
defp do_render(conn, num) do
|
||||
conn |> send_resp(200, render("page#{num}", conn))
|
||||
end
|
||||
|
||||
match _, do: send_resp(conn, 404, "Page not found.")
|
||||
end
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
defmodule Plug.Session.ETS do
|
||||
@moduledoc """
|
||||
Stores the session in an in-memory ETS table.
|
||||
This store does not create the ETS table; it expects that an
|
||||
existing named table with public properties is passed as an
|
||||
argument.
|
||||
We don't recommend using this store in production as every
|
||||
session will be stored in ETS and never cleaned until you
|
||||
create a task responsible for cleaning up old entries.
|
||||
Also, since the store is in-memory, it means sessions are
|
||||
not shared between servers. If you deploy to more than one
|
||||
machine, using this store is again not recommended.
|
||||
This store, however, can be used as an example for creating
|
||||
custom storages, based on Redis, Memcached, or a database
|
||||
itself.
|
||||
## Options
|
||||
* `:table` - ETS table name (required)
|
||||
For more information on ETS tables, visit the Erlang documentation at
|
||||
http://www.erlang.org/doc/man/ets.html.
|
||||
## Storage
|
||||
The data is stored in ETS in the following format:
|
||||
{sid :: String.t, data :: map, timestamp :: :erlang.timestamp}
|
||||
The timestamp is updated whenever there is a read or write to the
|
||||
table and it may be used to detect if a session is still active.
|
||||
## Examples
|
||||
# Create an ETS table when the application starts
|
||||
:ets.new(:session, [:named_table, :public, read_concurrency: true])
|
||||
# Use the session plug with the table name
|
||||
plug Plug.Session, store: :ets, key: "sid", table: :session
|
||||
"""
|
||||
|
||||
@behaviour Plug.Session.Store
|
||||
|
||||
@max_tries 100
|
||||
|
||||
def init(opts) do
|
||||
Keyword.fetch!(opts, :table)
|
||||
end
|
||||
|
||||
def get(_conn, sid, table) do
|
||||
case :ets.lookup(table, sid) do
|
||||
[{^sid, data, _timestamp}] ->
|
||||
:ets.update_element(table, sid, {3, now()})
|
||||
{sid, data}
|
||||
[] ->
|
||||
{nil, %{}}
|
||||
end
|
||||
end
|
||||
|
||||
def put(_conn, nil, data, table) do
|
||||
put_new(data, table)
|
||||
end
|
||||
|
||||
def put(_conn, sid, data, table) do
|
||||
:ets.insert(table, {sid, data, now()})
|
||||
sid
|
||||
end
|
||||
|
||||
def delete(_conn, sid, table) do
|
||||
:ets.delete(table, sid)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp put_new(data, table, counter \\ 0)
|
||||
when counter < @max_tries do
|
||||
sid = Base.encode64(:crypto.strong_rand_bytes(96))
|
||||
|
||||
if :ets.insert_new(table, {sid, data, now()}) do
|
||||
sid
|
||||
else
|
||||
put_new(data, table, counter + 1)
|
||||
end
|
||||
end
|
||||
|
||||
defp now() do
|
||||
:os.timestamp()
|
||||
end
|
||||
end
|
|
@ -6,8 +6,9 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<%= inspect(conn |> Map.from_struct |> Map.get(:private, %{}) |> Map.get(:plug_session)) %>
|
||||
<div id="content">
|
||||
<div id=<%= page %>>
|
||||
<div id=<%= page %> >
|
||||
<%= render.() %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Get ready to configure your Farmbot!
|
||||
|
||||
<form action="next">
|
||||
<button> Go! </button>
|
||||
<form action="next", method="post">
|
||||
<button> next </button>
|
||||
</form>
|
||||
|
|
|
@ -1,6 +1,64 @@
|
|||
Lets configure Network!
|
||||
<form action="next">
|
||||
<input> SSID </input>
|
||||
<input> PSK </input>
|
||||
<button> next </button>
|
||||
<script>
|
||||
window["ScanWifi"] = function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/scan_wifi", false);
|
||||
xhr.send();
|
||||
var resp = JSON.parse(xhr.responseText);
|
||||
var elem = document.getElementById("wifi");
|
||||
elem.hidden=false;
|
||||
|
||||
|
||||
var elem = document.getElementById("ssid");
|
||||
var opts = ""; for(var i = 0; i < resp.length; i++) {opts = opts + "<option value=" + resp[i] + " >" + resp[i] + "</option>\n"}
|
||||
elem.innerHTML = opts;
|
||||
}
|
||||
|
||||
window["UseEthernet"] = function() {
|
||||
var elem = document.getElementById("ethernet");
|
||||
elem.hidden=false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="next" method="post" enctype="multipart/form-data">
|
||||
<button type="button" onclick="ScanWifi()"> Scan for Wifi </button>
|
||||
<button type="button" onclick="UseEthernet()"> Use Ethernet </button>
|
||||
|
||||
<div id="wifi" hidden="true">
|
||||
<label for="ssid"> Select your SSID </label>
|
||||
<!-- This will get populated by the ScanWifi function. -->
|
||||
<select id="ssid" name="ssid"> </select>
|
||||
<label for="psk"> Password </label>
|
||||
<input id="psk" name="psk" type="password">
|
||||
|
||||
<button type="button" onclick="document.getElementById('wifi_static_settings').hidden=false;"> Use static settings </button>
|
||||
|
||||
<div id="wifi_static_settings" hidden="true" disabled="true">
|
||||
<label for="ipv4_address"> ip address </label>
|
||||
<input id="ipv4_address" name="ipv4_address">
|
||||
|
||||
<label for="ipv4_subnet_mask"> subnet mask </label>
|
||||
<input id="ipv4_subnet_mask" name="ipv4_subnet_mask">
|
||||
|
||||
<label for="nameservers"> ip address </label>
|
||||
<input id="nameservers" name="nameservers">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="ethernet" hidden="true">
|
||||
<button type="button" onclick="document.getElementById('eth_static_settings').hidden=false;"> Use static settings </button>
|
||||
|
||||
<div id="eth_static_settings" hidden="true">
|
||||
<label for="ipv4_address"> ip address </label>
|
||||
<input id="ipv4_address" name="ipv4_address">
|
||||
|
||||
<label for="ipv4_subnet_mask"> subnet mask </label>
|
||||
<input id="ipv4_subnet_mask" name="ipv4_subnet_mask">
|
||||
|
||||
<label for="nameservers"> ip address </label>
|
||||
<input id="nameservers" name="nameservers">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit"> next </button>
|
||||
</form>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Lets configure Network!
|
||||
<form action="next">
|
||||
Lets configure the Farmbot Web App
|
||||
<form action="next" enctype="multipart/form-data", method="post">
|
||||
<input> Email </input>
|
||||
<input> Password </input>
|
||||
<input> Server </input>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
Now lets configure your Arduino or Farmduino
|
||||
<form action="next" method="post">
|
||||
<label for="hardware"> Select your device </label>
|
||||
<select id="hardware" name="hardware">
|
||||
<option value="farmduino"> Farmduino </option>
|
||||
<option value="arduino"> Arduino Mega </option>
|
||||
</select>
|
||||
<button> next </button>
|
||||
</form>
|
|
@ -0,0 +1,23 @@
|
|||
Now lets configure your Arduino or Farmduino
|
||||
<script>
|
||||
window["SkipStep"] = function() {
|
||||
console.log("skipping step!");
|
||||
var elem = document.getElementById("submit_button");
|
||||
elem.disabled=false;
|
||||
}
|
||||
|
||||
window["FlashFW"] = function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/flash_fw", false);
|
||||
// xhr.setRequestHeader("content-type", "multipart/form-data");
|
||||
xhr.send("hello?");
|
||||
var elem = document.getElementById("submit_button");
|
||||
elem.disabled=false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="next" method="post">
|
||||
<button type="button" id="flash" onclick="FlashFW()"> Flash Firmware</button>
|
||||
<button type="button" id="skip" onclick="SkipStep()"> Skip this step </button>
|
||||
<input id="submit_button" type="submit" disabled="true" value="next">
|
||||
</form>
|
|
@ -0,0 +1,4 @@
|
|||
Congrats! Your device will now disconnect blah blah blah
|
||||
<form method="post" action="finish">
|
||||
<button> ok </button>
|
||||
<form>
|
Loading…
Reference in New Issue