Packages

Event notifications for network interfaces

Current section

Files

Jump to
inertial lib inertial.ex
Raw

lib/inertial.ex

defmodule Inertial do
@moduledoc """
Inertial provides system event notifications for network interface
changes such as link status and IP address assignments, on Linux and OSX.
It uses the OS's native event notification mechanisms to provide real-time
updates with minimal overhead. A connection is made to a 'system' socket
using the Erlang [`:socket`](`:socket`) module, and a NIF is used to set the appropriate
event filters and decode the received packets.
## Example
iex> ref = Inertial.subscribe()
#Reference<0.1234567890.1234567890.123456>
iex> receive do
...> {^ref, event} -> IO.inspect(event)
...> end
%{type: :new_addr, ifname: "eth0", addr: {192, 168, 1, 100}}
"""
@type link_event() :: %{type: :link_up | :link_down, ifname: String.t()}
@type addr_event() :: %{
type: :new_addr | :del_addr,
ifname: String.t(),
addr: :inet.ip_address()
}
@type event_msg() :: {reference(), link_event() | addr_event()}
@doc """
Subscribes the calling process to Inertial events.
Returns a reference that can be used to unsubscribe later, and identifies the event when
it arrives in the caller's mailbox. Messages will be of type `t:event_msg/0`.
## Example
iex> ref = Inertial.subscribe()
#Reference<0.1234567890.1234567890.123456>
iex> receive do
...> {^ref, event} -> IO.inspect(event)
...> end
%{type: :new_addr, ifname: "eth0", addr: {192, 168, 1, 100}}
"""
@spec subscribe() :: reference()
def subscribe() do
pid = self()
alias = Process.alias()
:ok = :gen_event.add_handler(Inertial.EventManager, {Inertial.Handler, alias}, {pid, alias})
alias
end
@doc """
Unsubscribes the calling process from Inertial events.
Takes the reference returned by `subscribe/0`, and unsubscribes. Should be called by the same
process that called `subscribe/0`.
Guarantees that no further messages with the given reference will be received after this call.
## Example
iex> ref = Inertial.subscribe()
#Reference<0.1234567890.1234567890.123456>
iex> Inertial.unsubscribe(ref)
:ok
"""
@spec unsubscribe(reference()) :: :ok
def unsubscribe(ref) when is_reference(ref) do
Process.unalias(ref)
:gen_event.delete_handler(Inertial.EventManager, {Inertial.Handler, ref}, [])
drain_late_events(ref)
end
defp drain_late_events(ref) do
receive do
{^ref, _event} -> drain_late_events(ref)
after
0 -> :ok
end
end
end