Skip to content

Commit

Permalink
Add interfaces monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
fhunleth committed May 9, 2019
1 parent 1fa83a2 commit 206e5dc
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/vintage_net/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ defmodule VintageNet.Application do

children = [
{VintageNet.PropertyTable, name: VintageNet},
VintageNet.InterfacesMonitor,
{VintageNet.ToElixir.Server, socket_path},
{VintageNet.NameResolver, args},
VintageNet.RouteManager,
Expand Down
73 changes: 73 additions & 0 deletions lib/vintage_net/interfaces_monitor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
defmodule VintageNet.InterfacesMonitor do
@moduledoc """
Monitor available interfaces
Currently this works by polling the system for what interfaces are visible. They may or may not be configured.
"""

use GenServer

alias VintageNet.PropertyTable

@refresh 30_000

@spec start_link(any()) :: GenServer.on_start()
def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end

@doc """
Return a list of interfaces
"""
@spec interfaces() :: [VintageNet.ifname()]
def interfaces() do
GenServer.call(__MODULE__, :interfaces)
end

@impl true
def init(_args) do
{:ok, refresh([]), @refresh}
end

@impl true
def handle_call(:interfaces, _from, old_names) do
new_names = refresh(old_names)
{:reply, new_names, new_names, @refresh}
end

@impl true
def handle_info(:timeout, old_names) do
new_names = refresh(old_names)
{:noreply, new_names, @refresh}
end

defp refresh(old_names) do
new_names = get_interfaces()

List.myers_difference(old_names, new_names)
|> Enum.each(&publish_deltas/1)

new_names
end

defp publish_deltas({:eq, _list}), do: :ok

defp publish_deltas({:del, list}) do
Enum.each(list, fn name -> PropertyTable.clear(VintageNet, property_name(name)) end)
end

defp publish_deltas({:ins, list}) do
Enum.each(list, fn name ->
PropertyTable.put(VintageNet, property_name(name), true)
end)
end

defp property_name(name) do
["interface", name, "present"]
end

defp get_interfaces() do
{:ok, addrs} = :inet.getifaddrs()
for {name, _info} <- addrs, do: to_string(name)
end
end
14 changes: 14 additions & 0 deletions test/interfaces_monitor_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule InterfacesMonitorTest do
use ExUnit.Case

alias VintageNet.InterfacesMonitor
doctest InterfacesMonitor

test "populates the property table" do
names = InterfacesMonitor.interfaces()

for name <- names do
assert true == VintageNet.get(["interface", name, "present"])
end
end
end

0 comments on commit 206e5dc

Please sign in to comment.