initial packets working

This commit is contained in:
Graham McIntire 2023-01-31 13:08:17 -06:00
parent f26d6321f2
commit 246cb43244
15 changed files with 215 additions and 45 deletions

View file

@ -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:
'&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
}).addTo(map);
// L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
// maxZoom: 19,
// attribution:
// '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
// }).addTo(map);
// let markerGroup = L.markerClusterGroup({
// removeOutsideVisibleBounds: true,

View file

@ -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

View file

@ -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

33
lib/aprs/archiver.ex Normal file
View file

@ -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

38
lib/aprs/data_extended.ex Normal file
View file

@ -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

View file

@ -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(

41
lib/aprs/packet.ex Normal file
View file

@ -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

9
lib/aprs/schema.ex Normal file
View file

@ -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

View file

@ -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<id: "phx-Fz9zBNjSOD3z4wAG", endpoint: AprsWeb.Endpoint, view: AprsWeb.PacketsLive.Index, parent_pid: nil, root_pid: #PID<0.785.0>, 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)}

View file

@ -3,5 +3,11 @@
</.header>
<.table id="packets" rows={@packets}>
<:col :let={packet} label="packet"><%= packet %></:col>
<:col :let={packet} label="sender"><%= packet.sender %></:col>
<:col :let={packet} label="ssid"><%= packet.ssid %></:col>
<:col :let={packet} label="base_callsign"><%= packet.base_callsign %></:col>
<:col :let={packet} label="data_type"><%= packet.data_type %></:col>
<:col :let={packet} label="destination"><%= packet.destination %></:col>
<:col :let={packet} label="information_field"><%= packet.information_field %></:col>
<:col :let={packet} label="path"><%= packet.path %></:col>
</.table>

View file

@ -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,

View file

@ -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"},

View file

@ -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"},

View file

@ -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

View file

@ -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