fix a couple DB stuffs, start work on farmware runtimne

pull/353/head
connor rigby 2017-05-25 12:31:26 -07:00
parent 09a3d69771
commit cf02cc35d2
8 changed files with 108 additions and 30 deletions

View File

@ -1 +1 @@
3.1.6
4.0.0

View File

@ -144,6 +144,12 @@ defmodule Farmbot.BotState do
GenServer.call(context.configuration, {:update_config, "user_env", map})
end
@doc """
Gets the user environment.
"""
@spec get_user_env(context) :: map
def get_user_env(%Context{} = ctx), do: get_config(ctx, :user_env)
@doc """
Locks the bot
"""

View File

@ -5,7 +5,16 @@ defmodule Farmbot.CeleryScript.Command.DataUpdate do
alias Farmbot.CeleryScript.Command
alias Farmbot.Database
require Logger
alias Database.Syncable.{
Device,
FarmEvent,
Peripheral,
Point,
Regimen,
Sequence,
Tool
}
use Farmbot.DebugLog
@behaviour Command
@typedoc """
@ -24,8 +33,12 @@ defmodule Farmbot.CeleryScript.Command.DataUpdate do
verb = parse_verb_str(verb)
Enum.each(pairs, fn(%{args: %{label: s, value: nowc}}) ->
syncable = s |> parse_syncable_str()
value = nowc |> parse_val_str()
:ok = Database.set_awaiting(context, syncable, verb, value)
if syncable do
value = nowc |> parse_val_str()
:ok = Database.set_awaiting(context, syncable, verb, value)
else
:ok
end
end)
context
end
@ -34,10 +47,19 @@ defmodule Farmbot.CeleryScript.Command.DataUpdate do
@type syncable :: Farmbot.Database.syncable
@spec parse_syncable_str(binary) :: syncable
defp parse_syncable_str("regimens"), do: Regimen
defp parse_syncable_str("peripherals"), do: Peripheral
defp parse_syncable_str("sequences"), do: Sequence
defp parse_syncable_str("farm_events"), do: FarmEvent
defp parse_syncable_str("tools"), do: Tool
defp parse_syncable_str("points"), do: Point
defp parse_syncable_str("devices"), do: Device
defp parse_syncable_str(str) do
Module.concat([Farmbot.Database.Syncable, Macro.camelize(str)])
debug_log "no such syncable: #{str}"
end
@spec parse_val_str(binary) :: number_or_wildcard
defp parse_val_str("*"), do: "*"
defp parse_val_str(int) when is_integer(int), do: int

View File

@ -43,17 +43,6 @@ defmodule Farmbot.Database do
@typedoc false
@type syncable_object :: map
@typedoc """
State of the DB
"""
@type state :: %{
by_kind_and_id: %{ required({syncable, db_id}) => ref_id },
awaiting: %{ required(syncable) => boolean },
by_kind: %{ required(syncable) => [ref_id] },
refs: %{ required(ref_id) => resource_map },
all: [ref_id],
}
# This pulls all the module names by their filename.
syncable_modules =
"lib/farmbot/database/syncable/"
@ -78,13 +67,20 @@ defmodule Farmbot.Database do
Farmbot.BotState.set_sync_msg(ctx, :syncing)
try do
for module_name <- all_syncable_modules() do
# see: `syncable.ex`. This is some macro magic.
debug_log "#{module_name} Sync begin."
:ok = module_name.fetch(ctx, {__MODULE__,
:commit_records, [ctx, module_name]})
if get_awaiting(ctx, module_name) do
# see: `syncable.ex`. This is some macro magic.
debug_log "#{module_name} Sync begin."
:ok = module_name.fetch(ctx, {__MODULE__,
:commit_records, [ctx, module_name]})
debug_log "#{module_name} Sync finish."
:ok = unset_awaiting(ctx, module_name)
:ok
else
debug_log "#{module_name} already up to date."
:ok
end
debug_log "#{module_name} Sync finish."
:ok
end
Farmbot.BotState.set_sync_msg(ctx, :synced)
:ok
@ -164,6 +160,38 @@ defmodule Farmbot.Database do
## GenServer
defmodule State do
@moduledoc false
alias Farmbot.Database.DB
defimpl Inspect, for: __MODULE__ do
def inspect(thing, _) do
"#DatabaseState<#{inspect thing.all}>"
end
end
defstruct [
:by_kind_and_id,
:awaiting,
:by_kind,
:refs,
:all
]
@type t :: %{
by_kind_and_id: %{ required({DB.syncable, DB.db_id}) => DB.ref_id },
awaiting: %{ required(DB.syncable) => boolean },
by_kind: %{ required(DB.syncable) => [DB.ref_id] },
refs: %{ required(DB.ref_id) => DB.resource_map },
all: [DB.ref_id],
}
end
@typedoc """
State of the DB
"""
@type state :: State.t
@doc """
Start the Database
"""
@ -176,7 +204,7 @@ defmodule Farmbot.Database do
initial_refs = %{}
initial_all = []
state = %{
state = %State{
by_kind_and_id: initial_by_kind_and_id,
awaiting: initial_awaiting,
by_kind: initial_by_kind,

View File

@ -3,13 +3,28 @@ defmodule Farmbot.Farmware.Runtime do
Executes a farmware
"""
use Farmbot.DebugLog
alias Farmbot.{Farmware, Context}
alias Farmbot.{Farmware, Context, BotState, Auth}
alias Farmware.RuntimeError, as: FarmwareRuntimeError
@doc """
Executes a Farmware inside a safe sandbox
"""
def execute(%Context{} = _ctx, %Farmware{} = _fw) do
raise FarmwareRuntimeError, "Farmware Runtime todo!"
def execute(%Context{} = ctx, %Farmware{} = fw) do
debug_log "Starting execution of #{inspect fw}"
env = environment(ctx)
end
defp environment(%Context{} = ctx) do
envs = BotState.get_user_env(ctx)
{:ok, %Farmbot.Token{} = tkn} = Auth.get_token(ctx.auth)
envs = Map.put(envs, "API_TOKEN", tkn)
Enum.map(envs, fn({key, val}) ->
{to_erl_safe(key), to_erl_safe(val)}
end)
end
defp to_erl_safe(%Farmbot.Token{encoded: enc}), do: to_erl_safe(enc)
defp to_erl_safe(binary) when is_binary(binary), do: to_charlist(binary)
defp to_erl_safe(map) when is_map(map), do: map |> Poison.encode! |> to_erl_safe()
end

View File

@ -8,7 +8,8 @@ defmodule Module.concat([Farmbot,System,"host"]) do
def factory_reset(reason) do
files = path() |> File.ls!()
Farmbot.System.FS.transaction fn() ->
File.rm_rf files
File.rm_rf! "#{path()}"
File.mkdir_p! "#{path()}"
File.write("#{path()}/factory_reset_reason", reason)
end, true
System.halt(0)

View File

@ -49,6 +49,9 @@ defmodule Farmbot.Transport.GenMqtt.Client do
|> Poison.decode!
|> Ast.parse
|> Command.do_command(context)
catch
:exit, thing ->
debug_log "caught a stray exit: #{inspect thing}"
rescue
e ->
Logger.error ">> Saved mqtt client from cs death: #{inspect e}"

View File

@ -36,14 +36,13 @@ defmodule Logger.Backends.FarmbotLogger do
"""
@type logger_level
:: :info
| :debug
| :warn
| :error
@typedoc """
One day this will me more
"""
@type channel :: :toast
@type channel :: :toast | :email
@type log_message
:: %{message: String.t,
@ -109,7 +108,7 @@ defmodule Logger.Backends.FarmbotLogger do
@spec do_post(Context.t, [log_message]) :: no_return
defp do_post(%Context{} = ctx, logs) do
try do
HTTP.post(ctx, "/api/logs", Poison.encode!(logs))
{:ok, %{status_code: 200}} = HTTP.post(ctx, "/api/logs", Poison.encode!(logs))
GenEvent.call(Elixir.Logger, __MODULE__, :post_success)
rescue
_ -> GenEvent.call(Elixir.Logger, __MODULE__, :post_fail)
@ -218,6 +217,10 @@ defmodule Logger.Backends.FarmbotLogger do
end
@spec build_log(String.t, number, rpc_log_type, [channel]) :: log_message
defp build_log(message, created_at, :debug, channels) do
build_log(message, created_at, :info, channels)
end
defp build_log(message, created_at, type, channels) do
%{message: message,
created_at: created_at,