diff --git a/assets/js/app.js b/assets/js/app.js
index bed25d0..2693fd8 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -65,27 +65,27 @@ window.addEventListener("phx:page-loading-stop", (_info) => {
// keyboard: true,
// }).setView([mapLatitude, mapLongitude], 12);
- var map = L.map("map").setView([51.505, -0.09], 13);
+ // var map = L.map("map").setView([51.505, -0.09], 13);
- let resizeMap = () => {
- const height = $(window).height();
- const width = $(window).width();
+ // let resizeMap = () => {
+ // const height = $(window).height();
+ // const width = $(window).width();
- document.querySelector("#map").height(height).width(width);
- map.invalidateSize();
- };
+ // document.querySelector("#map").height(height).width(width);
+ // map.invalidateSize();
+ // };
- // $(window)
- // .on("resize", () => {
- // resizeMap();
- // })
- // .trigger("resize");
+ // // $(window)
+ // // .on("resize", () => {
+ // // resizeMap();
+ // // })
+ // // .trigger("resize");
- L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
- maxZoom: 19,
- attribution:
- '© OpenStreetMap',
- }).addTo(map);
+ // L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
+ // maxZoom: 19,
+ // attribution:
+ // '© OpenStreetMap',
+ // }).addTo(map);
// let markerGroup = L.markerClusterGroup({
// removeOutsideVisibleBounds: true,
diff --git a/lib/aprs/accounts/user.ex b/lib/aprs/accounts/user.ex
index d1fbc36..351d62c 100644
--- a/lib/aprs/accounts/user.ex
+++ b/lib/aprs/accounts/user.ex
@@ -3,10 +3,10 @@ defmodule Aprs.Accounts.User do
import Ecto.Changeset
schema "users" do
- field :email, :string
- field :password, :string, virtual: true, redact: true
- field :hashed_password, :string, redact: true
- field :confirmed_at, :naive_datetime
+ field(:email, :string)
+ field(:password, :string, virtual: true, redact: true)
+ field(:hashed_password, :string, redact: true)
+ field(:confirmed_at, :naive_datetime)
timestamps()
end
diff --git a/lib/aprs/accounts/user_token.ex b/lib/aprs/accounts/user_token.ex
index 124e1a0..12c888d 100644
--- a/lib/aprs/accounts/user_token.ex
+++ b/lib/aprs/accounts/user_token.ex
@@ -14,10 +14,10 @@ defmodule Aprs.Accounts.UserToken do
@session_validity_in_days 60
schema "users_tokens" do
- field :token, :binary
- field :context, :string
- field :sent_to, :string
- belongs_to :user, Aprs.Accounts.User
+ field(:token, :binary)
+ field(:context, :string)
+ field(:sent_to, :string)
+ belongs_to(:user, Aprs.Accounts.User)
timestamps(updated_at: false)
end
@@ -56,10 +56,11 @@ defmodule Aprs.Accounts.UserToken do
"""
def verify_session_token_query(token) do
query =
- from token in token_and_context_query(token, "session"),
+ from(token in token_and_context_query(token, "session"),
join: user in assoc(token, :user),
where: token.inserted_at > ago(@session_validity_in_days, "day"),
select: user
+ )
{:ok, query}
end
@@ -114,10 +115,11 @@ defmodule Aprs.Accounts.UserToken do
days = days_for_context(context)
query =
- from token in token_and_context_query(hashed_token, context),
+ from(token in token_and_context_query(hashed_token, context),
join: user in assoc(token, :user),
where: token.inserted_at > ago(^days, "day") and token.sent_to == user.email,
select: user
+ )
{:ok, query}
@@ -149,8 +151,9 @@ defmodule Aprs.Accounts.UserToken do
hashed_token = :crypto.hash(@hash_algorithm, decoded_token)
query =
- from token in token_and_context_query(hashed_token, context),
+ from(token in token_and_context_query(hashed_token, context),
where: token.inserted_at > ago(@change_email_validity_in_days, "day")
+ )
{:ok, query}
@@ -163,17 +166,17 @@ defmodule Aprs.Accounts.UserToken do
Returns the token struct for the given token value and context.
"""
def token_and_context_query(token, context) do
- from UserToken, where: [token: ^token, context: ^context]
+ from(UserToken, where: [token: ^token, context: ^context])
end
@doc """
Gets all tokens for the given user for the given contexts.
"""
def user_and_contexts_query(user, :all) do
- from t in UserToken, where: t.user_id == ^user.id
+ from(t in UserToken, where: t.user_id == ^user.id)
end
def user_and_contexts_query(user, [_ | _] = contexts) do
- from t in UserToken, where: t.user_id == ^user.id and t.context in ^contexts
+ from(t in UserToken, where: t.user_id == ^user.id and t.context in ^contexts)
end
end
diff --git a/lib/aprs/archiver.ex b/lib/aprs/archiver.ex
new file mode 100644
index 0000000..fc970dd
--- /dev/null
+++ b/lib/aprs/archiver.ex
@@ -0,0 +1,33 @@
+defmodule Aprs.Archiver do
+ use GenServer
+ require Jason
+ require Logger
+
+ # alias Aprs.{Packet, Repo}
+ alias AprsWeb.Endpoint
+
+ @topic "call"
+
+ # API
+ @spec start_link(any) :: :ignore | {:error, any} | {:ok, pid}
+ def start_link(_args \\ []) do
+ GenServer.start_link(__MODULE__, [], name: :archiver)
+ end
+
+ # Callbacks
+
+ @spec init(any) :: {:ok, any}
+ def init(state \\ []) do
+ Process.send_after(self(), :connect, 5000)
+ Endpoint.subscribe(@topic)
+ {:ok, state}
+ end
+
+ def handle_info(:connect, state) do
+ {:noreply, state}
+ end
+
+ def handle_info(_msg, state) do
+ {:noreply, state}
+ end
+end
diff --git a/lib/aprs/data_extended.ex b/lib/aprs/data_extended.ex
new file mode 100644
index 0000000..f9a9798
--- /dev/null
+++ b/lib/aprs/data_extended.ex
@@ -0,0 +1,38 @@
+defmodule Aprs.DataExtended do
+ use Ecto.Schema
+ import Ecto.Changeset
+ alias Aprs.DataExtended
+
+ embedded_schema do
+ field :aprs_messaging, :boolean, default: false
+ field :comment, :string
+ field :data_type, :string
+ field :latitude, :decimal
+ field :longitude, :decimal
+ field :symbol_code, :string
+ field :symbol_table_id, :string
+ end
+
+ @doc false
+ def changeset(%DataExtended{} = data_extended, attrs) do
+ data_extended
+ |> cast(attrs, [
+ :aprs_messaging,
+ :comment,
+ :data_type,
+ :latitude,
+ :longitude,
+ :symbol_code,
+ :symbol_table_id
+ ])
+ |> validate_required([
+ :aprs_messaging,
+ :comment,
+ :data_type,
+ :latitude,
+ :longitude,
+ :symbol_code,
+ :symbol_table_id
+ ])
+ end
+end
diff --git a/lib/aprs/is/is.ex b/lib/aprs/is/is.ex
index fb0839c..f3f7d9c 100644
--- a/lib/aprs/is/is.ex
+++ b/lib/aprs/is/is.ex
@@ -15,7 +15,7 @@ defmodule Aprs.Is do
# Get startup parameters
server = Application.get_env(:aprs, :aprs_is_server, 'rotate.aprs2.net')
- port = Application.get_env(:aprs, :aprs_is_port, 14580)
+ port = Application.get_env(:aprs, :aprs_is_port, 14_580)
default_filter = Application.get_env(:aprs, :aprs_is_default_filter, "r/33/-96/100")
aprs_user_id = Application.get_env(:aprs, :aprs_is_login_id, "w5isp")
aprs_passcode = Application.get_env(:aprs, :aprs_is_password, "-1")
@@ -199,6 +199,7 @@ defmodule Aprs.Is do
# Registry.dispatch(Registry.PubSub, "aprs_messages", fn entries ->
# for {pid, _} <- entries, do: send(pid, {:broadcast, parsed_message})
# end)
+
AprsWeb.Endpoint.broadcast("aprs_messages", "packet", parsed_message)
# Phoenix.PubSub.broadcast(
diff --git a/lib/aprs/packet.ex b/lib/aprs/packet.ex
new file mode 100644
index 0000000..3e1f190
--- /dev/null
+++ b/lib/aprs/packet.ex
@@ -0,0 +1,41 @@
+defmodule Aprs.Packet do
+ use Aprs.Schema
+ import Ecto.Changeset
+ alias Aprs.DataExtended
+
+ schema "packets" do
+ field(:base_callsign, :string)
+ field(:data_type, :string)
+ field(:destination, :string)
+ field(:information_field, :string)
+ field(:path, :string)
+ field(:sender, :string)
+ field(:ssid, :string)
+ embeds_one(:data_extended, DataExtended)
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(packet, attrs) do
+ packet
+ |> cast(attrs, [
+ :base_callsign,
+ :data_type,
+ :destination,
+ :information_field,
+ :path,
+ :sender,
+ :ssid
+ ])
+ |> validate_required([
+ :base_callsign,
+ :data_type,
+ :destination,
+ :information_field,
+ :path,
+ :sender,
+ :ssid
+ ])
+ end
+end
diff --git a/lib/aprs/schema.ex b/lib/aprs/schema.ex
new file mode 100644
index 0000000..31b35b5
--- /dev/null
+++ b/lib/aprs/schema.ex
@@ -0,0 +1,9 @@
+defmodule Aprs.Schema do
+ defmacro __using__(_) do
+ quote do
+ use Ecto.Schema
+ @primary_key {:id, :binary_id, autogenerate: true}
+ @foreign_key_type :binary_id
+ end
+ end
+end
diff --git a/lib/aprs_web/live/packets_live/index.ex b/lib/aprs_web/live/packets_live/index.ex
index e4b9f09..c84987b 100644
--- a/lib/aprs_web/live/packets_live/index.ex
+++ b/lib/aprs_web/live/packets_live/index.ex
@@ -1,11 +1,24 @@
defmodule AprsWeb.PacketsLive.Index do
use AprsWeb, :live_view
+ alias AprsWeb.Endpoint
@impl true
def mount(_params, _session, socket) do
+ if connected?(socket) do
+ Endpoint.subscribe("aprs_messages")
+ end
+
{:ok, assign(socket, :packets, [])}
end
+ @impl true
+ def handle_info(%{event: "packet", payload: payload}, socket) do
+ socket = assign(socket, :packets, [payload | socket.assigns.packets])
+ {:noreply, socket}
+ end
+
+ # AprsWeb.PacketsLive.Index.handle_info(%Phoenix.Socket.Broadcast{topic: "aprs_messages", event: "packet", payload: %{base_callsign: "AE5PL", data_extended: %{aprs_messaging?: false, comment: "RNG0001 70cm Voice 441.1625MHz", data_type: :position, latitude: 33.26733333333333, longitude: -96.53266666666667, symbol_code: "&", symbol_table_id: "D"}, data_type: :position, destination: "APJI43", information_field: "!3316.04ND09631.96W&RNG0001 70cm Voice 441.1625MHz", path: "TCPIP*,qAC,AE5PL-IG", sender: "AE5PL-B", ssid: "B"}}, #Phoenix.LiveView.Socket, router: AprsWeb.Router, assigns: %{__changed__: %{}, flash: %{}, live_action: :index, packets: []}, transport_pid: #PID<0.776.0>, ...>)
+
# @impl true
# def handle_params(params, _url, socket) do
# {:noreply, apply_action(socket, socket.assigns.live_action, params)}
diff --git a/lib/aprs_web/live/packets_live/index.html.heex b/lib/aprs_web/live/packets_live/index.html.heex
index 3fde9ff..e6cfa9b 100644
--- a/lib/aprs_web/live/packets_live/index.html.heex
+++ b/lib/aprs_web/live/packets_live/index.html.heex
@@ -3,5 +3,11 @@
<.table id="packets" rows={@packets}>
- <:col :let={packet} label="packet"><%= packet %>
+ <:col :let={packet} label="sender"><%= packet.sender %>
+ <:col :let={packet} label="ssid"><%= packet.ssid %>
+ <:col :let={packet} label="base_callsign"><%= packet.base_callsign %>
+ <:col :let={packet} label="data_type"><%= packet.data_type %>
+ <:col :let={packet} label="destination"><%= packet.destination %>
+ <:col :let={packet} label="information_field"><%= packet.information_field %>
+ <:col :let={packet} label="path"><%= packet.path %>
diff --git a/lib/parser.ex b/lib/parser.ex
index ce11b89..d075ec0 100644
--- a/lib/parser.ex
+++ b/lib/parser.ex
@@ -3,6 +3,7 @@ defmodule Parser do
Main parsing library
"""
# import Bitwise
+ alias Aprs.Packet
alias Parser.Types.{MicE, Position}
require Logger
@@ -16,7 +17,9 @@ defmodule Parser do
[destination, path] <- String.split(path, ",", parts: 2),
data_extended <- parse_data(data_type, destination, data) do
{:ok,
- %{
+ %Packet{
+ # TODO: temporary for liveview
+ id: Ecto.UUID.generate(),
sender: sender,
path: path,
destination: destination,
diff --git a/mix.exs b/mix.exs
index 6936f2d..f9cfb20 100644
--- a/mix.exs
+++ b/mix.exs
@@ -37,7 +37,9 @@ defmodule Aprs.MixProject do
{:certifi, "~> 2.9"},
{:ecto_sql, "~> 3.6"},
{:finch, "~> 0.13"},
+ {:geo, "~> 3.4"},
{:geocalc, "~> 0.8"},
+ {:geo_postgis, "~> 3.4"},
{:heroicons, "~> 0.5"},
{:jason, "~> 1.2"},
{:libcluster, "~> 3.3"},
diff --git a/mix.lock b/mix.lock
index 410e14d..55c7d5d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -25,6 +25,8 @@
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"finch": {:hex, :finch, "0.14.0", "619bfdee18fc135190bf590356c4bf5d5f71f916adb12aec94caa3fa9267a4bc", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5459acaf18c4fdb47a8c22fb3baff5d8173106217c8e56c5ba0b93e66501a8dd"},
"floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"},
+ "geo": {:hex, :geo, "3.4.3", "0ddf3f681993d32c397e5ef346e7b4b6f36f39ed138502429832fa4000ebb9d5", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "e23f2892e5437ec8b063cee1beccec89c58fd841ae11133304700235feb25552"},
+ "geo_postgis": {:hex, :geo_postgis, "3.4.2", "5a3462b2a2271d6949ba355ceed0212dc89ecfd6d0073ff1dd8fd53de78af867", [:mix], [{:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0 or ~> 4.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "48d8c9f97f03805546db19217c42a57e972a3eb69fabaa3d11740285d25aaad4"},
"geocalc": {:hex, :geocalc, "0.8.5", "b9886679e44c323e5b72dcd90a64f834d775d2600af0b656ea9f07ccdacaa5a6", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3870c25c78513ec0456b69324c2be1af2202961002e81fb659559e3db162c802"},
"gettext": {:hex, :gettext, "0.22.0", "a25d71ec21b1848957d9207b81fd61cb25161688d282d58bdafef74c2270bdc4", [:mix], [{:expo, "~> 0.3.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "cb0675141576f73720c8e49b4f0fd3f2c69f0cd8c218202724d4aebab8c70ace"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
diff --git a/priv/repo/migrations/20230129191140_create_users_auth_tables.exs b/priv/repo/migrations/20230129191140_create_users_auth_tables.exs
index 324cafc..a5648f7 100644
--- a/priv/repo/migrations/20230129191140_create_users_auth_tables.exs
+++ b/priv/repo/migrations/20230129191140_create_users_auth_tables.exs
@@ -2,26 +2,26 @@ defmodule Aprs.Repo.Migrations.CreateUsersAuthTables do
use Ecto.Migration
def change do
- execute "CREATE EXTENSION IF NOT EXISTS citext", ""
+ execute("CREATE EXTENSION IF NOT EXISTS citext", "")
create table(:users) do
- add :email, :citext, null: false
- add :hashed_password, :string, null: false
- add :confirmed_at, :naive_datetime
+ add(:email, :citext, null: false)
+ add(:hashed_password, :string, null: false)
+ add(:confirmed_at, :naive_datetime)
timestamps()
end
- create unique_index(:users, [:email])
+ create(unique_index(:users, [:email]))
create table(:users_tokens) do
- add :user_id, references(:users, on_delete: :delete_all), null: false
- add :token, :binary, null: false
- add :context, :string, null: false
- add :sent_to, :string
+ add(:user_id, references(:users, on_delete: :delete_all), null: false)
+ add(:token, :binary, null: false)
+ add(:context, :string, null: false)
+ add(:sent_to, :string)
timestamps(updated_at: false)
end
- create index(:users_tokens, [:user_id])
- create unique_index(:users_tokens, [:context, :token])
+ create(index(:users_tokens, [:user_id]))
+ create(unique_index(:users_tokens, [:context, :token]))
end
end
diff --git a/priv/repo/migrations/20230131171908_create_packets.exs b/priv/repo/migrations/20230131171908_create_packets.exs
new file mode 100644
index 0000000..d0309ab
--- /dev/null
+++ b/priv/repo/migrations/20230131171908_create_packets.exs
@@ -0,0 +1,19 @@
+defmodule Aprs.Repo.Migrations.CreatePackets do
+ use Ecto.Migration
+
+ def change do
+ create table(:packets, primary_key: false) do
+ add(:id, :binary_id, primary_key: true)
+ add(:base_callsign, :string)
+ add(:data_type, :string)
+ add(:destination, :string)
+ add(:information_field, :string)
+ add(:path, :string)
+ add(:sender, :string)
+ add(:ssid, :string)
+ add(:data_extended, :map)
+
+ timestamps()
+ end
+ end
+end