Skip to content

Commit

Permalink
add initial functionality and version bump
Browse files Browse the repository at this point in the history
  • Loading branch information
derek-schaefer committed Nov 23, 2017
1 parent 9ced32e commit d8ad4ab
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 16 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
*.swp
*.tar

# The directory Mix will write compiled artifacts to.
/_build/

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# DDWRT
# DD-WRT Elixir Library

**TODO: Add description**

Expand Down
52 changes: 41 additions & 11 deletions lib/ddwrt.ex
Original file line number Diff line number Diff line change
@@ -1,18 +1,48 @@
defmodule DDWRT do
@moduledoc """
Documentation for DDWRT.
"""
alias DDWRT.{DHCP, Wireless}

@doc """
Hello world.
defstruct address: "http://192.168.1.1", username: "root", password: nil

## Examples
def status_wireless(%__MODULE__{} = settings) do
with {:ok, results} <- get_results(settings, "/Status_Wireless.live.asp"), do: results |> Wireless.new |> success
end

def status_lan(%__MODULE__{} = settings) do
with {:ok, results} <- get_results(settings, "/Status_Lan.live.asp"), do: results |> DHCP.new |> success
end

def get_results(%__MODULE__{} = settings, path) do
with {:ok, response} <- get(settings, path), do: response.body |> extract_results |> success
end

def get(%__MODULE__{} = settings, path) do
HTTPoison.get(settings.address <> path, headers(settings))
end

iex> DDWRT.hello
:world
def headers(%__MODULE__{} = settings) do
[authorization: "Basic " <> authorization(settings)]
end

"""
def hello do
:world
def authorization(%__MODULE__{} = settings) do
Base.encode64(settings.username <> ":" <> settings.password)
end

def extract_results(payload) do
Regex.scan(~r/{(\w+)::(.*)}/, payload)
|> Enum.map(&Enum.slice(&1, 1..2))
|> Enum.map(fn result -> Enum.map(result, &String.trim/1) end)
|> Map.new(&List.to_tuple/1)
end

def extract_entries(value) do
Regex.scan(~r/'((?:[^'\\]|\\.)*)'/, value)
|> Enum.map(&Enum.at(&1, 1))
|> Enum.map(&String.trim/1)
end

def extract_and_chunk_entries(value, size) do
value |> extract_entries |> Enum.chunk_every(size)
end

defp success(value), do: {:ok, value}
end
20 changes: 20 additions & 0 deletions lib/ddwrt/dhcp.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule DDWRT.DHCP do
alias DDWRT.DHCP.Lease

defstruct leases: []

@dhcp_leases "dhcp_leases"

def new(results) when is_map(results) do
%__MODULE__{
leases: leases(results)
}
end

defp leases(results) do
results
|> Map.fetch!(@dhcp_leases)
|> DDWRT.extract_and_chunk_entries(5)
|> Enum.map(&Lease.new/1)
end
end
12 changes: 12 additions & 0 deletions lib/ddwrt/dhcp/lease.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule DDWRT.DHCP.Lease do
defstruct [:name, :ip, :mac, :period]

def new(entry) when is_list(entry) do
%__MODULE__{
name: Enum.at(entry, 0),
ip: Enum.at(entry, 1),
mac: Enum.at(entry, 2),
period: Enum.at(entry, 3)
}
end
end
20 changes: 20 additions & 0 deletions lib/ddwrt/wireless.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule DDWRT.Wireless do
alias DDWRT.Wireless.Client

defstruct clients: []

@active_wireless "active_wireless"

def new(results) when is_map(results) do
%__MODULE__{
clients: clients(results)
}
end

defp clients(results) do
results
|> Map.fetch!(@active_wireless)
|> DDWRT.extract_and_chunk_entries(9)
|> Enum.map(&Client.new/1)
end
end
9 changes: 9 additions & 0 deletions lib/ddwrt/wireless/client.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule DDWRT.Wireless.Client do
defstruct [:mac]

def new(entry) when is_list(entry) do
%__MODULE__{
mac: Enum.at(entry, 0)
}
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule DDWRT.Mixfile do
def project do
[
app: :ddwrt,
version: "0.0.1",
version: "0.0.2",
elixir: "~> 1.5",
start_permanent: Mix.env == :prod,
description: description(),
Expand Down
15 changes: 15 additions & 0 deletions test/ddwrt/dhcp/lease_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule DDWRT.DHCP.LeaseTest do
use ExUnit.Case

alias DDWRT.DHCP.Lease

describe "#new" do
test "extracts from an empty entry list" do
assert Lease.new([]) == %Lease{}
end

test "extracts from a populated entry list" do
assert Lease.new(["name", "ip", "mac", "period"]) == %Lease{name: "name", ip: "ip", mac: "mac", period: "period"}
end
end
end
20 changes: 20 additions & 0 deletions test/ddwrt/dhcp_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule DDWRT.DHCPTest do
use ExUnit.Case

alias DDWRT.DHCP
alias DDWRT.DHCP.Lease

test "assigns default field values" do
assert %DHCP{} == %DHCP{leases: []}
end

describe "#new" do
test "extracts from an empty dhcp leases value" do
assert DHCP.new(%{"dhcp_leases" => ""}) == %DHCP{leases: []}
end

test "extracts from a populated dhcp leases value" do
assert DHCP.new(%{"dhcp_leases" => "'1','2','3','4','5','1','2','3','4','5'"}) == %DHCP{leases: [%Lease{ip: "2", mac: "3", name: "1", period: "4"}, %Lease{ip: "2", mac: "3", name: "1", period: "4"}]}
end
end
end
15 changes: 15 additions & 0 deletions test/ddwrt/wireless/client_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule DDWRT.Wireless.ClientTest do
use ExUnit.Case

alias DDWRT.Wireless.Client

describe "#new" do
test "extracts from an empty entry list" do
assert Client.new([]) == %Client{}
end

test "extracts from a populated entry list" do
assert Client.new(["mac"]) == %Client{mac: "mac"}
end
end
end
20 changes: 20 additions & 0 deletions test/ddwrt/wireless_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule DDWRT.WirelessTest do
use ExUnit.Case

alias DDWRT.Wireless
alias DDWRT.Wireless.Client

test "assigns default field values" do
assert %Wireless{} == %Wireless{clients: []}
end

describe "#new" do
test "extracts from an empty active wireless value" do
assert Wireless.new(%{"active_wireless" => ""}) == %Wireless{clients: []}
end

test "extracts from a populated active wireless value" do
assert Wireless.new(%{"active_wireless" => "'1','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7','8','9'"}) == %Wireless{clients: [%Client{mac: "1"}, %Client{mac: "1"}]}
end
end
end
93 changes: 90 additions & 3 deletions test/ddwrt_test.exs
Original file line number Diff line number Diff line change
@@ -1,8 +1,95 @@
defmodule DDWRTTest do
use ExUnit.Case
doctest DDWRT

test "greets the world" do
assert DDWRT.hello() == :world
setup do
ddwrt = %DDWRT{password: System.get_env("DDWRT_PASSWORD")}

{:ok, %{ddwrt: ddwrt}}
end

test "assigns default field values" do
assert %DDWRT{} == %DDWRT{address: "http://192.168.1.1", username: "root", password: nil}
end

describe "#get" do
@tag :external
test "requests from a result endpoint", %{ddwrt: ddwrt} do
assert {:ok, %HTTPoison.Response{}} = DDWRT.get(ddwrt, "/Status_Lan.live.asp")
end
end

describe "#get_results" do
@tag :external
test "requests and extracts from a results endpoint", %{ddwrt: ddwrt} do
assert {:ok, %{}} = DDWRT.get_results(ddwrt, "/Status_Lan.live.asp")
end
end

describe "#status_lan" do
@tag :external
test "requests and extracts from the lan status endpoint", %{ddwrt: ddwrt} do
assert {:ok, %DDWRT.DHCP{}} = DDWRT.status_lan(ddwrt)
end
end

describe "#status_wireless" do
@tag :external
test "requests and extracts from the wireless status endpoint", %{ddwrt: ddwrt} do
assert {:ok, %DDWRT.Wireless{}} = DDWRT.status_wireless(ddwrt)
end
end

describe "#extract_results" do
test "extracts from an empty payload" do
assert DDWRT.extract_results("") == %{}
end

test "extracts from a payload with one result" do
assert DDWRT.extract_results("{key::value}") == %{"key" => "value"}
end

test "extracts from a payload with multiple results" do
assert DDWRT.extract_results("{key1::value1}\n{key2::value2}") == %{"key1" => "value1", "key2" => "value2"}
end
end

describe "#extract_entries" do
test "extracts from an empty result value" do
assert DDWRT.extract_entries("") == []
end

test "extracts from a result value with one entry" do
assert DDWRT.extract_entries("'test'") == ["test"]
end

test "extracts from a result value with multiple entries" do
assert DDWRT.extract_entries("'test1','test2'") == ["test1", "test2"]
end
end

describe "#extract_and_chunk_entries" do
test "extracts and chunks from an empty result value" do
assert DDWRT.extract_and_chunk_entries("", 2) == []
end

test "extracts and chunks from a result value with one entry" do
assert DDWRT.extract_and_chunk_entries("'test'", 2) == [["test"]]
end

test "extracts and chunks from a result value with multiple entries" do
assert DDWRT.extract_and_chunk_entries("'test1','test2','test3','test4'", 2) == [["test1", "test2"], ["test3", "test4"]]
end
end

describe "#headers" do
test "builds a header keyword list with an authorization value" do
assert %DDWRT{username: "test", password: "test"} |> DDWRT.headers == [authorization: "Basic " <> Base.encode64("test:test")]
end
end

describe "#authorization" do
test "builds an authorization value using the username and password" do
assert %DDWRT{username: "test", password: "test"} |> DDWRT.authorization == Base.encode64("test:test")
end
end
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ExUnit.configure(exclude: [:external])
ExUnit.start()

0 comments on commit d8ad4ab

Please sign in to comment.