making progress

pull/363/head
connor rigby 2017-09-13 09:29:10 -07:00
parent b6b3020702
commit 94e3a21970
11 changed files with 186 additions and 126 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,4 @@
Congrats! Your device will now disconnect blah blah blah
<form method="post" action="finish">
<button> ok </button>
<form>