farmbot_os/lib/system/farmbot_system_network.ex

188 lines
4.9 KiB
Elixir

defmodule Farmbot.System.Network do
@moduledoc """
Network functionality.
"""
require Logger
use GenServer
alias Farmbot.System.FS.ConfigStorage, as: CS
alias Farmbot.System.Network.SSH
alias Farmbot.System.Network.Ntp
alias Farmbot.Auth
@spec mod(atom) :: atom
defp mod(target), do: Module.concat([Farmbot, System, target, Network])
def init(target) do
Logger.info ">> is starting networking"
m = mod(target)
{:ok, _cb} = m.start_link
{:ok, interface_config} = get_config("interfaces")
parse_and_start_config(interface_config, m)
{:ok, target}
end
# if networking is disabled.
defp parse_and_start_config(nil, _), do: spawn(fn ->
Process.sleep(2000)
{:ok, fpf} = GenServer.call(CS, {:get, Configuration, "first_party_farmware"})
if fpf, do: Farmware.get_first_party_farmware
Farmbot.Auth.try_log_in
end)
defp parse_and_start_config(config, m) do
for {interface, settings} <- config do
m.start_interface(interface, settings)
end
end
@doc """
Starts the network manager
"""
def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end
@doc """
Scans for wireless ssids.
"""
@spec scan(String.t) :: [String.t]
def scan(interface_name) do
GenServer.call(__MODULE__, {:scan, interface_name})
end
@doc """
Lists all network interfaces that Farmbot Detected.
"""
@spec enumerate :: [String.t] | {:error, term}
def enumerate do
GenServer.call(__MODULE__, :enumerate)
end
@doc """
Restarts networking services. This will block.
"""
def restart do
stop_all()
{:ok, interface_config} = get_config("interfaces")
m = mod(get_mod())
parse_and_start_config(interface_config, m)
end
@doc """
Starts an interface
"""
def start_interface(interface, settings) do
GenServer.call(__MODULE__, {:start, interface, settings}, :infinity)
end
@doc """
Stops an interface
"""
def stop_interface(interface) do
GenServer.call(__MODULE__, {:stop, interface}, :infinity)
end
@doc """
Stops all interfaces
"""
def stop_all do
{:ok, interfaces} = get_config("interfaces")
if interfaces do
for {iface, _} <- interfaces do
stop_interface(iface)
end
end
end
@doc """
Connected to the World Wide Web. Should be called from the
callback module.
"""
def on_connect(fun \\ nil) do
# this happens because on wifi we try to do stuff before linux is
# finished setting stuff up.
Process.sleep(2000)
if fun, do: fun.()
Logger.info ">> is connected to the World Wide Web."
Logger.info ">> is reading configurations."
{:ok, ssh} = get_config("ssh")
{:ok, ntp} = get_config("ntp")
# First Party Farmware is not really a network concern but here we are...
{:ok, fpf} = GenServer.call(CS, {:get, Configuration, "first_party_farmware"})
IO.puts "FIRST PARTY FIRMWARE BOOL: #{inspect fpf}"
if ntp do
Logger.info ">> ntp"
Ntp.set_time
end
try do
if ssh do
Logger.info ">> ssh"
spawn SSH, :start_link, []
end
rescue
error -> Logger.warn(">> Failed to start ssh: #{inspect error}")
end
try do
if fpf, do: Farmware.get_first_party_farmware
rescue
error -> Logger.warn(">> Failed to install farmwares: #{inspect error}")
end
Logger.info ">> Login"
r = Auth.try_log_in!
if r == {:error, :timeout}, do: Auth.try_log_in!, else: r
end
@spec get_config(String.t) :: {:ok, any}
defp get_config(key), do: GenServer.call(CS, {:get, Network, key})
# @spec get_config() :: {:ok, false | map}
# defp get_config, do: GenServer.call(CS, {:get, Network, :all})
defp get_mod, do: GenServer.call(__MODULE__, :get_mod)
# GENSERVER STUFF
def handle_call(:get_mod, _, target), do: {:reply, target, target}
def handle_call({:scan, interface_name}, _, target) do
f = mod(target).scan(interface_name)
{:reply, f, target}
end
def handle_call(:enumerate, _, target) do
f = mod(target).enumerate
{:reply, f, target}
end
def handle_call({:start, interface, settings}, _, target) do
f = mod(target).start_interface(interface, settings)
{:reply, f, target}
end
def handle_call({:stop, interface}, _, target) do
f = mod(target).stop_interface(interface)
{:reply, f, target}
end
def terminate(reason, target) do
ssh_pid = Process.whereis(SSH)
if ssh_pid do
SSH.stop(reason)
end
target_pid = Process.whereis(mod(target))
if target_pid do
GenServer.stop(target_pid, reason)
end
end
# Behavior
@type return_type :: :ok | {:error, term}
@callback scan(String.t) :: [String.t] | {:error, term}
@callback enumerate() :: [String.t] | {:error, term}
@callback start_interface(String.t, map) :: return_type
@callback stop_interface(String.t) :: return_type
@callback start_link :: {:ok, pid}
end