Add sanatizer for send_message.
This commit is contained in:
parent
c23a6bbc04
commit
c08e37e148
|
@ -36,7 +36,7 @@ defmodule Farmbot.BotState.Transport.GenMQTT do
|
|||
|
||||
def handle_log_events(logs, {%{client: client} = internal_state, old_bot_state}) do
|
||||
for %Farmbot.Log{} = log <- logs do
|
||||
if log.module == nil or Module.split(log.module || Elixir.Logger) |> List.first == "Farmbot" do
|
||||
if log.module != nil or Module.split(log.module || Elixir.Logger) |> List.first == "Farmbot" and (log.verbosity || 0) < 3 do
|
||||
location_data = Map.get(old_bot_state || %{}, :location_data, %{position: %{x: -1, y: -1, z: -1}})
|
||||
meta = %{type: log.level, x: nil, y: nil, z: nil}
|
||||
log_without_pos = %{created_at: log.time, meta: meta, channels: log.meta[:channels] || [], message: log.message}
|
||||
|
|
|
@ -7,41 +7,90 @@ defmodule Farmbot.CeleryScript.AST.Node.SendMessage do
|
|||
def execute(%{message: m, message_type: type}, channels, env) do
|
||||
env = mutate_env(env)
|
||||
{:ok, env, channels} = do_reduce(channels, env, [])
|
||||
msg = String.replace(m, "{{", "<%=")
|
||||
|> String.replace("}}", "%>")
|
||||
|> EEx.eval_string(fetch_bindings())
|
||||
|
||||
case type do
|
||||
"debug" ->
|
||||
Logger.debug 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"info" ->
|
||||
Logger.info 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"busy" ->
|
||||
Logger.busy 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"success" ->
|
||||
Logger.success 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"warn" ->
|
||||
Logger.warn 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"error" ->
|
||||
Logger.error 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
other ->
|
||||
{:error, "unknown type: #{other}", env}
|
||||
bindings = fetch_bindings()
|
||||
case sanatize(m) do
|
||||
{:ok, sanatized} ->
|
||||
msg = EEx.eval_string(sanatized, bindings)
|
||||
case type do
|
||||
"debug" ->
|
||||
Logger.debug 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"info" ->
|
||||
Logger.info 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"busy" ->
|
||||
Logger.busy 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"success" ->
|
||||
Logger.success 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"warn" ->
|
||||
Logger.warn 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
"error" ->
|
||||
Logger.error 2, msg, channels: channels
|
||||
{:ok, env}
|
||||
other ->
|
||||
{:error, "unknown type: #{other}", env}
|
||||
end
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
end
|
||||
|
||||
rescue
|
||||
e in CompileError ->
|
||||
{:error, Exception.message(e), env}
|
||||
case Exception.message(e) do
|
||||
"nofile:1: undefined function " <> undef ->
|
||||
Logger.error 2, "Unknown variable: #{undef}"
|
||||
{:error, :unknown_variable, env}
|
||||
_ ->
|
||||
{:error, Exception.message(e), env}
|
||||
end
|
||||
e -> reraise(e, System.stacktrace())
|
||||
end
|
||||
|
||||
defp sanatize(message, global_acc \\ "", local_acc \\ "", mode \\ :global)
|
||||
|
||||
defp sanatize(<<>>, global, _local, _mode), do: {:ok, global}
|
||||
|
||||
defp sanatize(<<"{{", rest :: binary >>, acc, _local, _mode) do
|
||||
sanatize(rest, acc <> "<%=", "", :local)
|
||||
end
|
||||
|
||||
defp sanatize(<<"}}", rest ::binary >>, global_acc, local_acc, _) do
|
||||
case sanatize_local(local_acc) do
|
||||
{:ok, sanatized} ->
|
||||
sanatize(rest, global_acc <> sanatized <> "%>", "", :global)
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
defp sanatize(<<char, rest :: binary>>, global, _local, :global) do
|
||||
sanatize(rest, global <> <<char>>, "", :global)
|
||||
end
|
||||
|
||||
defp sanatize(<<char, rest :: binary>>, global, local, :local) do
|
||||
sanatize(rest, global, local <> <<char>>, :local)
|
||||
end
|
||||
|
||||
defp sanatize_local(local) do
|
||||
cond do
|
||||
String.contains?(local, "(") or String.contains?(local, ")") ->
|
||||
{:error, "templates may not contain special characters: `(` or `)`"}
|
||||
String.contains?(local, ".") ->
|
||||
{:error, "templates may not contain special character: `.`"}
|
||||
String.contains?(local, ":") ->
|
||||
{:error, "templates may not contain special character: `.`"}
|
||||
String.contains?(local, "[") or String.contains?(local, "]") ->
|
||||
{:error, "templates may not contain special characters: `[` or `]`"}
|
||||
String.contains?(local, "\"") or String.contains?(local, "\'") or String.contains?(local, "\`") ->
|
||||
{:error, "templates may not sub strings."}
|
||||
true -> {:ok, local}
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch_bindings do
|
||||
bot_state = Farmbot.BotState.force_state_push()
|
||||
pins = Enum.map(bot_state.pins, fn({pin, %{value: value}}) -> {pin, value} end)
|
||||
pins = Enum.map(bot_state.pins, fn({pin, %{value: value}}) -> {:"pin_#{pin}", value} end)
|
||||
location = Enum.map(bot_state.location_data.position, fn({axis, val}) -> {axis, val} end)
|
||||
pins ++ location
|
||||
end
|
||||
|
|
|
@ -19,11 +19,19 @@ defmodule Farmbot.FarmEvent.Manager do
|
|||
|
||||
@checkup_time 20_000
|
||||
|
||||
def wait_for_sync do
|
||||
GenServer.call(__MODULE__, :wait_for_sync)
|
||||
end
|
||||
|
||||
def resume do
|
||||
GenServer.call(__MODULE__, :resume)
|
||||
end
|
||||
|
||||
## GenServer
|
||||
|
||||
defmodule State do
|
||||
@moduledoc false
|
||||
defstruct [timer: nil, last_time_index: %{}]
|
||||
defstruct [timer: nil, last_time_index: %{}, wait_for_sync: true]
|
||||
end
|
||||
|
||||
@doc false
|
||||
|
@ -32,11 +40,29 @@ defmodule Farmbot.FarmEvent.Manager do
|
|||
end
|
||||
|
||||
def init([]) do
|
||||
send self(), :checkup
|
||||
{:ok, struct(State)}
|
||||
end
|
||||
|
||||
def handle_info(:checkup, state) do
|
||||
def handle_call(:wait_for_sync, _, state) do
|
||||
if state.timer do
|
||||
Process.cancel_timer(state.timer)
|
||||
end
|
||||
Logger.warn 3, "Pausing FarmEvent Execution until sync."
|
||||
{:reply, :ok, %{state | wait_for_sync: true}}
|
||||
end
|
||||
|
||||
def handle_call(:resume, _, state) do
|
||||
send self(), :checkup
|
||||
Logger.success 3, "Resuming FarmEvents."
|
||||
{:reply, :ok, %{state | wait_for_sync: false}}
|
||||
end
|
||||
|
||||
def handle_info(:checkup, %{wait_for_sync: true} = state) do
|
||||
Logger.warn 3, "Waiting for sync before running FarmEvents."
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(:checkup, %{wait_for_sync: false} = state) do
|
||||
now = get_now()
|
||||
|
||||
all_events = Farmbot.Repo.current_repo().all(Farmbot.Repo.FarmEvent)
|
||||
|
@ -156,6 +182,15 @@ defmodule Farmbot.FarmEvent.Manager do
|
|||
# Checks if we shoudl run a sequence or not. returns {event | nil, time | nil}
|
||||
defp should_run_sequence?(calendar, last_time, now)
|
||||
|
||||
defp should_run_sequence?(nil, last_time, now) do
|
||||
Logger.debug 3, "Checking sequence with no calendar."
|
||||
if is_nil(last_time) do
|
||||
{true, now}
|
||||
else
|
||||
{false, last_time}
|
||||
end
|
||||
end
|
||||
|
||||
# if there is no last time, check if time is passed now within 60 seconds.
|
||||
defp should_run_sequence?([first_time | _], nil, now) do;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ defmodule Farmbot.FarmEvent.Supervisor do
|
|||
|
||||
def init([]) do
|
||||
children = [
|
||||
# worker(Farmbot.FarmEvent.Manager, [])
|
||||
worker(Farmbot.FarmEvent.Manager, [])
|
||||
]
|
||||
|
||||
supervise(children, strategy: :one_for_one)
|
||||
|
|
|
@ -59,11 +59,17 @@ defmodule Farmbot.Repo do
|
|||
def init([repo_a, repo_b]) do
|
||||
# Delete any old sync cmds.
|
||||
destroy_all_sync_cmds()
|
||||
if Process.whereis(Farmbot.FarmEvent.Manager) do
|
||||
Farmbot.FarmEvent.Manager.wait_for_sync()
|
||||
end
|
||||
|
||||
needs_hard_sync = if ConfigStorage.get_config_value(:bool, "settings", "first_sync") || auto_sync?() do
|
||||
do_sync_both(repo_a, repo_b)
|
||||
ConfigStorage.update_config_value(:bool, "settings", "first_sync", false)
|
||||
BotState.set_sync_status(:synced)
|
||||
if Process.whereis(Farmbot.FarmEvent.Manager) do
|
||||
Farmbot.FarmEvent.Manager.resume()
|
||||
end
|
||||
false
|
||||
else
|
||||
BotState.set_sync_status(:sync_now)
|
||||
|
@ -90,6 +96,7 @@ defmodule Farmbot.Repo do
|
|||
def handle_call(:force_hard_sync, _, state) do
|
||||
maybe_cancel_timer(state.timer)
|
||||
BotState.set_sync_status(:sync_now)
|
||||
Farmbot.FarmEvent.Manager.wait_for_sync()
|
||||
{:reply, :ok, %{state | timer: nil, needs_hard_sync: true}}
|
||||
end
|
||||
|
||||
|
@ -103,6 +110,7 @@ defmodule Farmbot.Repo do
|
|||
|
||||
def handle_call(:flip, _, %{repos: [repo_a, repo_b], needs_hard_sync: true} = state) do
|
||||
maybe_cancel_timer(state.timer)
|
||||
Farmbot.FarmEvent.Manager.wait_for_sync()
|
||||
destroy_all_sync_cmds()
|
||||
Logger.warn 3, "Forcing full sync."
|
||||
BotState.set_sync_status(:syncing)
|
||||
|
@ -110,12 +118,14 @@ defmodule Farmbot.Repo do
|
|||
BotState.set_sync_status(:synced)
|
||||
copy_configs(repo_b)
|
||||
flip_repos_in_cs()
|
||||
Farmbot.FarmEvent.Manager.resume()
|
||||
{:reply, :ok, %{state | repos: [repo_b, repo_a], needs_hard_sync: false, timer: start_timer()}}
|
||||
end
|
||||
|
||||
def handle_call(:flip, _, %{repos: [repo_a, repo_b]} = state) do
|
||||
maybe_cancel_timer(state.timer)
|
||||
Logger.busy 3, "Syncing"
|
||||
Farmbot.FarmEvent.Manager.wait_for_sync()
|
||||
BotState.set_sync_status(:syncing)
|
||||
|
||||
# Fetch all sync_cmds and apply them in order they were received.
|
||||
|
@ -128,6 +138,7 @@ defmodule Farmbot.Repo do
|
|||
copy_configs(repo_b)
|
||||
destroy_all_sync_cmds()
|
||||
Logger.success 3, "Sync complete."
|
||||
Farmbot.FarmEvent.Manager.resume()
|
||||
{:reply, repo_b, %{state | repos: [repo_b, repo_a], timer: start_timer()}}
|
||||
end
|
||||
|
||||
|
@ -247,7 +258,7 @@ defmodule Farmbot.Repo do
|
|||
case repo.get(mod, id) do
|
||||
# If it does not, just return the newly created object.
|
||||
nil ->
|
||||
mod.changeset(obj, %{})
|
||||
mod.changeset(struct(mod), not_struct)
|
||||
|> repo.insert!
|
||||
|
||||
# if there is an existing record, copy the ecto meta from the old
|
||||
|
|
|
@ -83,7 +83,7 @@ defmodule Farmbot.Target.Bootstrap.Configurator.Router do
|
|||
email = ConfigStorage.get_config_value(:string, "authorization", "email")
|
||||
pass = ConfigStorage.get_config_value(:string, "authorization", "password")
|
||||
server = ConfigStorage.get_config_value(:string, "authorization", "server")
|
||||
network = !(Enum.empty?(ConfigStorage.all(ConfigStorage.NetworkInterface.NetworkInterface)))
|
||||
network = !(Enum.empty?(ConfigStorage.all(ConfigStorage.NetworkInterface)))
|
||||
if email && pass && server && network do
|
||||
conn = render_page(conn, "finish")
|
||||
spawn fn() ->
|
||||
|
|
Loading…
Reference in a new issue