parent
afb9fcc538
commit
44a80cd5eb
15 changed files with 155 additions and 3234 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -100,7 +100,7 @@ profiles.json
|
|||
.stride_auth.md
|
||||
|
||||
|
||||
# Gleam build artifacts
|
||||
# Build artifacts
|
||||
/build/
|
||||
|
||||
# Generated by nix, machine-specific paths
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
erlang 28.3
|
||||
elixir 1.19.5-otp-28
|
||||
#elixir 1.20.0-rc.1-otp-28
|
||||
gleam 1.15.2
|
||||
nodejs 22.22.2
|
||||
|
|
|
|||
14
Dockerfile
14
Dockerfile
|
|
@ -34,29 +34,21 @@ RUN apt-get update \
|
|||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends build-essential git curl libsnmp-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Gleam compiler
|
||||
ARG GLEAM_VERSION=1.15.2
|
||||
RUN curl -fsSL https://github.com/gleam-lang/gleam/releases/download/v${GLEAM_VERSION}/gleam-v${GLEAM_VERSION}-x86_64-unknown-linux-musl.tar.gz \
|
||||
| tar xz -C /usr/local/bin/
|
||||
|
||||
# prepare build dir
|
||||
WORKDIR /app
|
||||
|
||||
# set build ENV
|
||||
ENV MIX_ENV="prod"
|
||||
|
||||
# install hex + rebar + mix_gleam archive (must use cache mounts so they
|
||||
# persist into subsequent cache-mounted steps)
|
||||
# install hex + rebar (must use cache mounts so they persist into subsequent cache-mounted steps)
|
||||
RUN --mount=type=cache,target=/root/.hex \
|
||||
--mount=type=cache,target=/root/.mix \
|
||||
mix local.hex --force \
|
||||
&& mix local.rebar --force \
|
||||
&& mix archive.install hex mix_gleam --force
|
||||
&& mix local.rebar --force
|
||||
|
||||
# install mix dependencies
|
||||
COPY mix.exs mix.lock gleam.toml ./
|
||||
COPY mix.exs mix.lock ./
|
||||
COPY vendor vendor
|
||||
COPY src src
|
||||
RUN --mount=type=cache,target=/root/.hex \
|
||||
--mount=type=cache,target=/root/.mix \
|
||||
mix deps.get --only $MIX_ENV
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -29,16 +29,10 @@ RUN apt-get update \
|
|||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Gleam compiler
|
||||
ARG GLEAM_VERSION=1.15.2
|
||||
RUN curl -fsSL https://github.com/gleam-lang/gleam/releases/download/v${GLEAM_VERSION}/gleam-v${GLEAM_VERSION}-x86_64-unknown-linux-musl.tar.gz \
|
||||
| tar xz -C /usr/local/bin/
|
||||
|
||||
# Install hex + rebar + mix_gleam archive (matches k8s/Dockerfile exactly)
|
||||
# Install hex + rebar (matches k8s/Dockerfile exactly)
|
||||
# This step takes ~10 seconds on every deploy, so we bake it in
|
||||
RUN mix local.hex --force \
|
||||
&& mix local.rebar --force \
|
||||
&& mix archive.install hex mix_gleam --force
|
||||
&& mix local.rebar --force
|
||||
|
||||
# Set build ENV
|
||||
ENV MIX_ENV="prod"
|
||||
|
|
|
|||
|
|
@ -51,9 +51,6 @@ defmodule Towerops.EctoTypes.MacAddress do
|
|||
MAC addresses are stored as VARCHAR(17) in the database (sufficient for
|
||||
colon-separated format). No database migrations are required when adopting
|
||||
this custom type - Ecto handles conversion transparently.
|
||||
|
||||
Parsing and formatting logic is implemented in Gleam at
|
||||
`src/towerops/ecto_types/mac_address.gleam`.
|
||||
"""
|
||||
use Ecto.Type
|
||||
|
||||
|
|
@ -79,7 +76,7 @@ defmodule Towerops.EctoTypes.MacAddress do
|
|||
def cast(binary) when is_binary(binary) and byte_size(binary) == 6 do
|
||||
# Check if it's a 6-byte binary (not a 6-character string)
|
||||
if String.printable?(binary) do
|
||||
# It's a short string, try string parsing via Gleam
|
||||
# It's a short string, try string parsing
|
||||
cast_from_string(binary)
|
||||
else
|
||||
# It's a binary MAC address (SNMP format)
|
||||
|
|
|
|||
|
|
@ -74,11 +74,11 @@ defmodule Towerops.Agent.HeartbeatMetadata do
|
|||
defstruct version: "", hostname: "", uptime_seconds: 0
|
||||
|
||||
def encode(%__MODULE__{} = m) do
|
||||
:towerops@proto@encode.encode_heartbeat_metadata({:heartbeat_metadata, m.version, m.hostname, m.uptime_seconds})
|
||||
Towerops.Proto.TupleEncode.encode_heartbeat_metadata({:heartbeat_metadata, m.version, m.hostname, m.uptime_seconds})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_heartbeat_metadata(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_heartbeat_metadata(binary) do
|
||||
{:ok, {:heartbeat_metadata, version, hostname, uptime}} ->
|
||||
%__MODULE__{version: version, hostname: hostname, uptime_seconds: uptime}
|
||||
|
||||
|
|
@ -93,11 +93,11 @@ defmodule Towerops.Agent.HeartbeatResponse do
|
|||
defstruct status: ""
|
||||
|
||||
def encode(%__MODULE__{} = r) do
|
||||
:towerops@proto@encode.encode_heartbeat_response({:heartbeat_response, r.status})
|
||||
Towerops.Proto.TupleEncode.encode_heartbeat_response({:heartbeat_response, r.status})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_heartbeat_response(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_heartbeat_response(binary) do
|
||||
{:ok, {:heartbeat_response, status}} -> %__MODULE__{status: status}
|
||||
{:error, _} -> %__MODULE__{}
|
||||
end
|
||||
|
|
@ -109,7 +109,8 @@ defmodule Towerops.Agent.SnmpConfig do
|
|||
defstruct enabled: false, version: "", community: "", port: 0, transport: ""
|
||||
|
||||
def encode(%__MODULE__{} = s) do
|
||||
:towerops@proto@encode.encode_snmp_config({:snmp_config, s.enabled, s.version, s.community, s.port, s.transport})
|
||||
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
||||
Towerops.Proto.TupleEncode.encode_snmp_config({:snmp_config, s.enabled, s.version, s.community, s.port, s.transport})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -123,11 +124,11 @@ defmodule Towerops.Agent.Sensor do
|
|||
defstruct id: "", type: "", oid: "", divisor: 0.0, unit: "", metadata: %{}
|
||||
|
||||
def encode(%__MODULE__{} = s) do
|
||||
:towerops@proto@encode.encode_sensor({:sensor, s.id, s.type, s.oid, s.divisor, s.unit, s.metadata})
|
||||
Towerops.Proto.TupleEncode.encode_sensor({:sensor, s.id, s.type, s.oid, s.divisor, s.unit, s.metadata})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_sensor(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_sensor(binary) do
|
||||
{:ok, {:sensor, id, type, oid, divisor, unit, meta}} ->
|
||||
%__MODULE__{
|
||||
id: id,
|
||||
|
|
@ -149,11 +150,11 @@ defmodule Towerops.Agent.Interface do
|
|||
defstruct id: "", if_index: 0, if_name: ""
|
||||
|
||||
def encode(%__MODULE__{} = i) do
|
||||
:towerops@proto@encode.encode_interface({:interface, i.id, i.if_index, i.if_name})
|
||||
Towerops.Proto.TupleEncode.encode_interface({:interface, i.id, i.if_index, i.if_name})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
_ = :towerops@proto@decode.decode_device(binary)
|
||||
_ = Towerops.Proto.TupleDecode.decode_device(binary)
|
||||
%__MODULE__{}
|
||||
end
|
||||
end
|
||||
|
|
@ -191,7 +192,7 @@ defmodule Towerops.Agent.Device do
|
|||
{:interface, i.id, i.if_index, i.if_name}
|
||||
end)
|
||||
|
||||
:towerops@proto@encode.encode_device(
|
||||
Towerops.Proto.TupleEncode.encode_device(
|
||||
{:device, d.id, d.name, d.ip_address, snmp, d.poll_interval_seconds, sensors, interfaces, d.monitoring_enabled,
|
||||
d.check_interval_seconds}
|
||||
)
|
||||
|
|
@ -205,7 +206,7 @@ defmodule Towerops.Agent.AgentConfig do
|
|||
defstruct version: "", poll_interval_seconds: 0, devices: [], checks: []
|
||||
|
||||
def encode(%__MODULE__{} = c) do
|
||||
checks = Enum.map(c.checks, &Towerops.Proto.Agent.check_to_gleam/1)
|
||||
checks = Enum.map(c.checks, &Towerops.Proto.Agent.check_to_tuple/1)
|
||||
|
||||
device_tuples =
|
||||
Enum.map(c.devices, fn %Device{} = d ->
|
||||
|
|
@ -233,11 +234,11 @@ defmodule Towerops.Agent.AgentConfig do
|
|||
end)
|
||||
|
||||
config = {:agent_config, c.version, c.poll_interval_seconds, device_tuples, checks}
|
||||
:towerops@proto@encode.encode_agent_config(config)
|
||||
Towerops.Proto.TupleEncode.encode_agent_config(config)
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_agent_config(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_agent_config(binary) do
|
||||
{:ok, {:agent_config, version, poll_interval, _devices, _checks}} ->
|
||||
%__MODULE__{version: version, poll_interval_seconds: poll_interval}
|
||||
|
||||
|
|
@ -252,7 +253,7 @@ defmodule Towerops.Agent.SensorReading do
|
|||
defstruct sensor_id: "", value: 0.0, status: "", timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = sr) do
|
||||
:towerops@proto@encode.encode_sensor_reading({:sensor_reading, sr.sensor_id, sr.value, sr.status, sr.timestamp})
|
||||
Towerops.Proto.TupleEncode.encode_sensor_reading({:sensor_reading, sr.sensor_id, sr.value, sr.status, sr.timestamp})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -269,7 +270,7 @@ defmodule Towerops.Agent.InterfaceStat do
|
|||
timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = s) do
|
||||
:towerops@proto@encode.encode_interface_stat(
|
||||
Towerops.Proto.TupleEncode.encode_interface_stat(
|
||||
{:interface_stat, s.interface_id, s.if_in_octets, s.if_out_octets, s.if_in_errors, s.if_out_errors,
|
||||
s.if_in_discards, s.if_out_discards, s.timestamp}
|
||||
)
|
||||
|
|
@ -292,7 +293,7 @@ defmodule Towerops.Agent.NeighborDiscovery do
|
|||
timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = n) do
|
||||
gleam_tuple = {
|
||||
tuple_data = {
|
||||
:neighbor_discovery,
|
||||
n.interface_id,
|
||||
n.protocol,
|
||||
|
|
@ -307,7 +308,7 @@ defmodule Towerops.Agent.NeighborDiscovery do
|
|||
n.timestamp
|
||||
}
|
||||
|
||||
:towerops@proto@encode.encode_neighbor_discovery(gleam_tuple)
|
||||
Towerops.Proto.TupleEncode.encode_neighbor_discovery(tuple_data)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -316,13 +317,13 @@ defmodule Towerops.Agent.MonitoringCheck do
|
|||
defstruct device_id: "", status: "", response_time_ms: 0.0, timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = mc) do
|
||||
:towerops@proto@encode.encode_monitoring_check(
|
||||
Towerops.Proto.TupleEncode.encode_monitoring_check(
|
||||
{:monitoring_check, mc.device_id, mc.status, mc.response_time_ms, mc.timestamp}
|
||||
)
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_monitoring_check(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_monitoring_check(binary) do
|
||||
{:ok, {:monitoring_check, device_id, status, response_time_ms, timestamp}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
|
@ -333,7 +334,7 @@ defmodule Towerops.Agent.MonitoringCheck do
|
|||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -343,8 +344,8 @@ defmodule Towerops.Agent.Metric do
|
|||
defstruct metric_type: nil
|
||||
|
||||
def encode(%__MODULE__{metric_type: mt}) do
|
||||
gleam_metric = Towerops.Proto.Agent.metric_to_gleam(mt)
|
||||
:towerops@proto@encode.encode_metric(gleam_metric)
|
||||
metric_tuple = Towerops.Proto.Agent.metric_to_tuple(mt)
|
||||
Towerops.Proto.TupleEncode.encode_metric(metric_tuple)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -353,24 +354,24 @@ defmodule Towerops.Agent.MetricBatch do
|
|||
defstruct metrics: []
|
||||
|
||||
def encode(%__MODULE__{} = batch) do
|
||||
gleam_metrics =
|
||||
metric_tuples =
|
||||
Enum.map(batch.metrics, fn %Towerops.Agent.Metric{metric_type: mt} ->
|
||||
Towerops.Proto.Agent.metric_to_gleam(mt)
|
||||
Towerops.Proto.Agent.metric_to_tuple(mt)
|
||||
end)
|
||||
|
||||
:towerops@proto@encode.encode_metric_batch({:metric_batch, gleam_metrics})
|
||||
Towerops.Proto.TupleEncode.encode_metric_batch({:metric_batch, metric_tuples})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_metric_batch(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_metric_batch(binary) do
|
||||
{:ok, {:metric_batch, metrics}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
metrics: Enum.map(metrics, &Towerops.Proto.Agent.gleam_metric_to_elixir/1)
|
||||
metrics: Enum.map(metrics, &Towerops.Proto.Agent.tuple_to_metric/1)
|
||||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -426,13 +427,13 @@ defmodule Towerops.Agent.CheckResult do
|
|||
defstruct check_id: "", status: 0, output: "", response_time_ms: 0.0, timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = cr) do
|
||||
:towerops@proto@encode.encode_check_result(
|
||||
Towerops.Proto.TupleEncode.encode_check_result(
|
||||
{:check_result, cr.check_id, cr.status, cr.output, cr.response_time_ms, cr.timestamp}
|
||||
)
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_check_result(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_check_result(binary) do
|
||||
{:ok, {:check_result, check_id, status, output, response_time_ms, timestamp}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
|
@ -444,7 +445,7 @@ defmodule Towerops.Agent.CheckResult do
|
|||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -454,8 +455,8 @@ defmodule Towerops.Agent.CheckList do
|
|||
defstruct checks: []
|
||||
|
||||
def encode(%__MODULE__{} = cl) do
|
||||
gleam_checks = Enum.map(cl.checks, &Towerops.Proto.Agent.check_to_gleam/1)
|
||||
:towerops@proto@encode.encode_check_list({:check_list, gleam_checks})
|
||||
check_tuples = Enum.map(cl.checks, &Towerops.Proto.Agent.check_to_tuple/1)
|
||||
Towerops.Proto.TupleEncode.encode_check_list({:check_list, check_tuples})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -475,7 +476,7 @@ defmodule Towerops.Agent.SnmpDevice do
|
|||
transport: ""
|
||||
|
||||
def encode(%__MODULE__{} = d) do
|
||||
:towerops@proto@encode.encode_snmp_device(
|
||||
Towerops.Proto.TupleEncode.encode_snmp_device(
|
||||
{:snmp_device, d.ip, d.community, d.version, d.port, d.v3_security_level, d.v3_username, d.v3_auth_protocol,
|
||||
d.v3_auth_password, d.v3_priv_protocol, d.v3_priv_password, d.transport}
|
||||
)
|
||||
|
|
@ -487,8 +488,8 @@ defmodule Towerops.Agent.SnmpQuery do
|
|||
defstruct query_type: :GET, oids: []
|
||||
|
||||
def encode(%__MODULE__{} = q) do
|
||||
:towerops@proto@encode.encode_snmp_query(
|
||||
{:snmp_query, Towerops.Proto.Agent.query_type_atom_to_gleam(q.query_type), q.oids}
|
||||
Towerops.Proto.TupleEncode.encode_snmp_query(
|
||||
{:snmp_query, Towerops.Proto.Agent.query_type_to_atom(q.query_type), q.oids}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -513,17 +514,17 @@ defmodule Towerops.Agent.AgentJobList do
|
|||
defstruct jobs: []
|
||||
|
||||
def encode(%__MODULE__{} = jl) do
|
||||
gleam_jobs = Enum.map(jl.jobs, &Towerops.Proto.Agent.job_to_gleam/1)
|
||||
:towerops@proto@encode.encode_agent_job_list({:agent_job_list, gleam_jobs})
|
||||
job_tuples = Enum.map(jl.jobs, &Towerops.Proto.Agent.job_to_tuple/1)
|
||||
Towerops.Proto.TupleEncode.encode_agent_job_list({:agent_job_list, job_tuples})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_agent_job_list(binary) do
|
||||
{:ok, {:agent_job_list, gleam_jobs}} ->
|
||||
{:ok, %__MODULE__{jobs: Enum.map(gleam_jobs, &Towerops.Proto.Agent.gleam_job_to_elixir/1)}}
|
||||
case Towerops.Proto.TupleDecode.decode_agent_job_list(binary) do
|
||||
{:ok, {:agent_job_list, job_tuples}} ->
|
||||
{:ok, %__MODULE__{jobs: Enum.map(job_tuples, &Towerops.Proto.Agent.tuple_to_job/1)}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -540,17 +541,17 @@ defmodule Towerops.Agent.AgentJob do
|
|||
mikrotik_commands: []
|
||||
|
||||
def encode(%__MODULE__{} = j) do
|
||||
gleam_job = Towerops.Proto.Agent.job_to_gleam(j)
|
||||
:towerops@proto@encode.encode_agent_job(gleam_job)
|
||||
job_tuple = Towerops.Proto.Agent.job_to_tuple(j)
|
||||
Towerops.Proto.TupleEncode.encode_agent_job(job_tuple)
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_agent_job(binary) do
|
||||
{:ok, gleam_job} ->
|
||||
{:ok, Towerops.Proto.Agent.gleam_job_to_elixir(gleam_job)}
|
||||
case Towerops.Proto.TupleDecode.decode_agent_job(binary) do
|
||||
{:ok, job_tuple} ->
|
||||
{:ok, Towerops.Proto.Agent.tuple_to_job(job_tuple)}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -629,11 +630,11 @@ defmodule Towerops.Agent.AgentError do
|
|||
defstruct device_id: "", job_id: "", message: "", timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = e) do
|
||||
:towerops@proto@encode.encode_agent_error({:agent_error, e.device_id, e.job_id, e.message, e.timestamp})
|
||||
Towerops.Proto.TupleEncode.encode_agent_error({:agent_error, e.device_id, e.job_id, e.message, e.timestamp})
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_agent_error(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_agent_error(binary) do
|
||||
{:ok, {:agent_error, device_id, job_id, message, timestamp}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
|
@ -644,7 +645,7 @@ defmodule Towerops.Agent.AgentError do
|
|||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -654,13 +655,13 @@ defmodule Towerops.Agent.CredentialTestResult do
|
|||
defstruct test_id: "", success: false, error_message: "", system_description: "", timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = r) do
|
||||
:towerops@proto@encode.encode_credential_test_result(
|
||||
Towerops.Proto.TupleEncode.encode_credential_test_result(
|
||||
{:credential_test_result, r.test_id, r.success, r.error_message, r.system_description, r.timestamp}
|
||||
)
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_credential_test_result(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_credential_test_result(binary) do
|
||||
{:ok, {:credential_test_result, test_id, success, error_message, system_description, timestamp}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
|
@ -672,7 +673,7 @@ defmodule Towerops.Agent.CredentialTestResult do
|
|||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -694,18 +695,18 @@ defmodule Towerops.Agent.MikrotikResult do
|
|||
defstruct device_id: "", job_id: "", sentences: [], error: "", timestamp: 0
|
||||
|
||||
def encode(%__MODULE__{} = r) do
|
||||
gleam_sentences =
|
||||
sentence_tuples =
|
||||
Enum.map(r.sentences, fn %MikrotikSentence{attributes: attrs} ->
|
||||
{:mikrotik_sentence, attrs}
|
||||
end)
|
||||
|
||||
:towerops@proto@encode.encode_mikrotik_result(
|
||||
{:mikrotik_result, r.device_id, r.job_id, gleam_sentences, r.error, r.timestamp}
|
||||
Towerops.Proto.TupleEncode.encode_mikrotik_result(
|
||||
{:mikrotik_result, r.device_id, r.job_id, sentence_tuples, r.error, r.timestamp}
|
||||
)
|
||||
end
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_mikrotik_result(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_mikrotik_result(binary) do
|
||||
{:ok, {:mikrotik_result, device_id, job_id, sentences, error, timestamp}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
|
@ -722,7 +723,7 @@ defmodule Towerops.Agent.MikrotikResult do
|
|||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -742,7 +743,7 @@ defmodule Towerops.Agent.LldpTopologyResult do
|
|||
defstruct device_id: "", job_id: "", local_system_name: "", neighbors: [], timestamp: 0
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case :towerops@proto@decode.decode_lldp_topology_result(binary) do
|
||||
case Towerops.Proto.TupleDecode.decode_lldp_topology_result(binary) do
|
||||
{:ok, {:lldp_topology_result, device_id, job_id, local_system_name, neighbors, timestamp}} ->
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
|
@ -763,7 +764,7 @@ defmodule Towerops.Agent.LldpTopologyResult do
|
|||
}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, Towerops.Proto.Agent.gleam_error_to_elixir(reason)}
|
||||
{:error, Towerops.Proto.Agent.decode_error_to_tuple(reason)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -784,24 +785,24 @@ defmodule Towerops.Proto.Agent do
|
|||
alias Towerops.Agent.SnmpDevice
|
||||
alias Towerops.Agent.SnmpQuery
|
||||
|
||||
# Convert Gleam DecodeError to Elixir {atom, string} tuple.
|
||||
# Convert DecodeError to Elixir {atom, string} tuple.
|
||||
# Most error tags pass through unchanged; :wire_error maps to :decode_error.
|
||||
def gleam_error_to_elixir({:wire_error, msg}), do: {:decode_error, msg}
|
||||
def gleam_error_to_elixir({tag, msg}) when is_atom(tag) and is_binary(msg), do: {tag, msg}
|
||||
def gleam_error_to_elixir(other), do: {:decode_error, inspect(other)}
|
||||
def decode_error_to_tuple({:wire_error, msg}), do: {:decode_error, msg}
|
||||
def decode_error_to_tuple({tag, msg}) when is_atom(tag) and is_binary(msg), do: {tag, msg}
|
||||
def decode_error_to_tuple(other), do: {:decode_error, inspect(other)}
|
||||
|
||||
# Convert Elixir metric tagged tuple to Gleam metric variant
|
||||
def metric_to_gleam({:sensor_reading, %SensorReading{} = sr}) do
|
||||
# Convert Elixir metric tagged tuple to metric tuple
|
||||
def metric_to_tuple({:sensor_reading, %SensorReading{} = sr}) do
|
||||
{:sensor_reading_metric, {:sensor_reading, sr.sensor_id, sr.value, sr.status, sr.timestamp}}
|
||||
end
|
||||
|
||||
def metric_to_gleam({:interface_stat, %InterfaceStat{} = is}) do
|
||||
def metric_to_tuple({:interface_stat, %InterfaceStat{} = is}) do
|
||||
{:interface_stat_metric,
|
||||
{:interface_stat, is.interface_id, is.if_in_octets, is.if_out_octets, is.if_in_errors, is.if_out_errors,
|
||||
is.if_in_discards, is.if_out_discards, is.timestamp}}
|
||||
end
|
||||
|
||||
def metric_to_gleam({:neighbor_discovery, %NeighborDiscovery{} = nd}) do
|
||||
def metric_to_tuple({:neighbor_discovery, %NeighborDiscovery{} = nd}) do
|
||||
tuple = {
|
||||
:neighbor_discovery,
|
||||
nd.interface_id,
|
||||
|
|
@ -820,17 +821,17 @@ defmodule Towerops.Proto.Agent do
|
|||
{:neighbor_discovery_metric, tuple}
|
||||
end
|
||||
|
||||
def metric_to_gleam({:monitoring_check, %MonitoringCheck{} = mc}) do
|
||||
def metric_to_tuple({:monitoring_check, %MonitoringCheck{} = mc}) do
|
||||
{:monitoring_check_metric, {:monitoring_check, mc.device_id, mc.status, mc.response_time_ms, mc.timestamp}}
|
||||
end
|
||||
|
||||
def metric_to_gleam({:check_result, %CheckResult{} = cr}) do
|
||||
def metric_to_tuple({:check_result, %CheckResult{} = cr}) do
|
||||
{:check_result_metric, {:check_result, cr.check_id, cr.status, cr.output, cr.response_time_ms, cr.timestamp}}
|
||||
end
|
||||
|
||||
# Convert Gleam metric variant to Elixir metric struct
|
||||
def gleam_metric_to_elixir(gleam_metric) do
|
||||
case gleam_metric do
|
||||
# Convert metric tuple to Elixir metric struct
|
||||
def tuple_to_metric(metric_tuple) do
|
||||
case metric_tuple do
|
||||
{:sensor_reading_metric, {:sensor_reading, sensor_id, value, status, timestamp}} ->
|
||||
%Metric{
|
||||
metric_type:
|
||||
|
|
@ -909,7 +910,7 @@ defmodule Towerops.Proto.Agent do
|
|||
end
|
||||
|
||||
# Job type conversions
|
||||
def job_type_atom_to_gleam(atom) when is_atom(atom) do
|
||||
def job_type_to_atom(atom) when is_atom(atom) do
|
||||
case atom do
|
||||
:DISCOVER -> :discover
|
||||
:POLL -> :poll
|
||||
|
|
@ -921,8 +922,8 @@ defmodule Towerops.Proto.Agent do
|
|||
end
|
||||
end
|
||||
|
||||
def gleam_job_type_to_atom(gleam_jt) do
|
||||
case gleam_jt do
|
||||
def atom_to_job_type(job_type_atom) do
|
||||
case job_type_atom do
|
||||
:discover -> :DISCOVER
|
||||
:poll -> :POLL
|
||||
:mikrotik -> :MIKROTIK
|
||||
|
|
@ -933,7 +934,7 @@ defmodule Towerops.Proto.Agent do
|
|||
end
|
||||
end
|
||||
|
||||
def query_type_atom_to_gleam(atom) do
|
||||
def query_type_to_atom(atom) do
|
||||
case atom do
|
||||
:GET -> :get
|
||||
:WALK -> :walk
|
||||
|
|
@ -941,30 +942,28 @@ defmodule Towerops.Proto.Agent do
|
|||
end
|
||||
end
|
||||
|
||||
def gleam_query_type_to_atom(gleam_qt) do
|
||||
case gleam_qt do
|
||||
def atom_to_query_type(query_type_atom) do
|
||||
case query_type_atom do
|
||||
:get -> :GET
|
||||
:walk -> :WALK
|
||||
other -> other
|
||||
end
|
||||
end
|
||||
|
||||
# Convert Gleam AgentJob tuple to Elixir struct
|
||||
def gleam_job_to_elixir(
|
||||
{:agent_job, job_id, job_type, device_id, snmp_device, queries, mikrotik_device, mikrotik_commands}
|
||||
) do
|
||||
# Convert AgentJob tuple to Elixir struct
|
||||
def tuple_to_job({:agent_job, job_id, job_type, device_id, snmp_device, queries, mikrotik_device, mikrotik_commands}) do
|
||||
%AgentJob{
|
||||
job_id: job_id,
|
||||
job_type: gleam_job_type_to_atom(job_type),
|
||||
job_type: atom_to_job_type(job_type),
|
||||
device_id: device_id,
|
||||
snmp_device: gleam_optional_snmp_device(snmp_device),
|
||||
queries: Enum.map(queries, &gleam_query_to_elixir/1),
|
||||
mikrotik_device: gleam_optional_mikrotik_device(mikrotik_device),
|
||||
mikrotik_commands: Enum.map(mikrotik_commands, &gleam_mikrotik_command_to_elixir/1)
|
||||
snmp_device: tuple_optional_snmp_device(snmp_device),
|
||||
queries: Enum.map(queries, &tuple_to_query/1),
|
||||
mikrotik_device: tuple_optional_mikrotik_device(mikrotik_device),
|
||||
mikrotik_commands: Enum.map(mikrotik_commands, &tuple_to_mikrotik_command/1)
|
||||
}
|
||||
end
|
||||
|
||||
defp gleam_optional_snmp_device(
|
||||
defp tuple_optional_snmp_device(
|
||||
{:some, {:snmp_device, ip, community, version, port, v3sl, v3u, v3ap, v3apw, v3pp, v3ppw, transport}}
|
||||
) do
|
||||
%SnmpDevice{
|
||||
|
|
@ -982,13 +981,13 @@ defmodule Towerops.Proto.Agent do
|
|||
}
|
||||
end
|
||||
|
||||
defp gleam_optional_snmp_device(:none), do: nil
|
||||
defp tuple_optional_snmp_device(:none), do: nil
|
||||
|
||||
defp gleam_query_to_elixir({:snmp_query, qt, oids}) do
|
||||
%SnmpQuery{query_type: gleam_query_type_to_atom(qt), oids: oids}
|
||||
defp tuple_to_query({:snmp_query, qt, oids}) do
|
||||
%SnmpQuery{query_type: atom_to_query_type(qt), oids: oids}
|
||||
end
|
||||
|
||||
defp gleam_optional_mikrotik_device({:some, {:mikrotik_device, ip, port, username, password, use_ssl, ssh_port}}) do
|
||||
defp tuple_optional_mikrotik_device({:some, {:mikrotik_device, ip, port, username, password, use_ssl, ssh_port}}) do
|
||||
%MikrotikDevice{
|
||||
ip: ip,
|
||||
port: port,
|
||||
|
|
@ -999,14 +998,14 @@ defmodule Towerops.Proto.Agent do
|
|||
}
|
||||
end
|
||||
|
||||
defp gleam_optional_mikrotik_device(:none), do: nil
|
||||
defp tuple_optional_mikrotik_device(:none), do: nil
|
||||
|
||||
defp gleam_mikrotik_command_to_elixir({:mikrotik_command, command, args}) do
|
||||
defp tuple_to_mikrotik_command({:mikrotik_command, command, args}) do
|
||||
%MikrotikCommand{command: command, args: args}
|
||||
end
|
||||
|
||||
# Convert Elixir AgentJob struct to Gleam tuple
|
||||
def job_to_gleam(%AgentJob{} = j) do
|
||||
# Convert Elixir AgentJob struct to tuple
|
||||
def job_to_tuple(%AgentJob{} = j) do
|
||||
snmp_device =
|
||||
case j.snmp_device do
|
||||
nil ->
|
||||
|
|
@ -1020,7 +1019,7 @@ defmodule Towerops.Proto.Agent do
|
|||
|
||||
queries =
|
||||
Enum.map(j.queries, fn %SnmpQuery{} = q ->
|
||||
{:snmp_query, query_type_atom_to_gleam(q.query_type), q.oids}
|
||||
{:snmp_query, query_type_to_atom(q.query_type), q.oids}
|
||||
end)
|
||||
|
||||
mikrotik_device =
|
||||
|
|
@ -1037,12 +1036,12 @@ defmodule Towerops.Proto.Agent do
|
|||
{:mikrotik_command, mc.command, mc.args}
|
||||
end)
|
||||
|
||||
{:agent_job, j.job_id, job_type_atom_to_gleam(j.job_type), j.device_id, snmp_device, queries, mikrotik_device,
|
||||
{:agent_job, j.job_id, job_type_to_atom(j.job_type), j.device_id, snmp_device, queries, mikrotik_device,
|
||||
mikrotik_commands}
|
||||
end
|
||||
|
||||
# Convert Elixir Check struct to Gleam tuple
|
||||
def check_to_gleam(%Towerops.Agent.Check{} = c) do
|
||||
# Convert Elixir Check struct to tuple
|
||||
def check_to_tuple(%Towerops.Agent.Check{} = c) do
|
||||
config =
|
||||
cond do
|
||||
c.http != nil ->
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
defmodule :towerops@proto@decode do
|
||||
defmodule Towerops.Proto.TupleDecode do
|
||||
@moduledoc """
|
||||
Erlang compatibility wrapper for decoding protobuf messages.
|
||||
Converts Elixir structs to Gleam-style tuples for backward compatibility.
|
||||
Compatibility wrapper for decoding protobuf messages.
|
||||
Converts Elixir structs to tagged tuples for backward compatibility.
|
||||
"""
|
||||
|
||||
alias Towerops.Agent.MikrotikCommand
|
||||
|
|
@ -81,13 +81,13 @@ defmodule :towerops@proto@decode do
|
|||
def decode_mikrotik_result(binary) when is_binary(binary) do
|
||||
case Decode.decode_mikrotik_result(binary) do
|
||||
{:ok, %Types.MikrotikResult{} = mr} ->
|
||||
# Convert MikrotikSentence structs to Gleam tuples
|
||||
gleam_sentences =
|
||||
# Convert MikrotikSentence structs to tuples
|
||||
tuple_sentences =
|
||||
Enum.map(mr.sentences, fn %Types.MikrotikSentence{attributes: attrs} ->
|
||||
{:mikrotik_sentence, attrs}
|
||||
end)
|
||||
|
||||
{:ok, {:mikrotik_result, mr.device_id, mr.job_id, gleam_sentences, mr.error, mr.timestamp}}
|
||||
{:ok, {:mikrotik_result, mr.device_id, mr.job_id, tuple_sentences, mr.error, mr.timestamp}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
|
@ -121,26 +121,26 @@ defmodule :towerops@proto@decode do
|
|||
def decode_metric_batch(binary) when is_binary(binary) do
|
||||
case Decode.decode_metric_batch(binary) do
|
||||
{:ok, %Types.MetricBatch{metrics: metrics}} ->
|
||||
# Convert metrics to Gleam-style tuples
|
||||
gleam_metrics = Enum.map(metrics, &metric_to_gleam/1)
|
||||
{:ok, {:metric_batch, gleam_metrics}}
|
||||
# Convert metrics to tagged tuples
|
||||
tuple_metrics = Enum.map(metrics, &metric_to_tuple/1)
|
||||
{:ok, {:metric_batch, tuple_metrics}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
defp metric_to_gleam({:sensor_reading, %Types.SensorReading{} = sr}) do
|
||||
defp metric_to_tuple({:sensor_reading, %Types.SensorReading{} = sr}) do
|
||||
{:sensor_reading_metric, {:sensor_reading, sr.sensor_id, sr.value, sr.status, sr.timestamp}}
|
||||
end
|
||||
|
||||
defp metric_to_gleam({:interface_stat, %Types.InterfaceStat{} = is}) do
|
||||
defp metric_to_tuple({:interface_stat, %Types.InterfaceStat{} = is}) do
|
||||
{:interface_stat_metric,
|
||||
{:interface_stat, is.interface_id, is.if_in_octets, is.if_out_octets, is.if_in_errors, is.if_out_errors,
|
||||
is.if_in_discards, is.if_out_discards, is.timestamp}}
|
||||
end
|
||||
|
||||
defp metric_to_gleam({:neighbor_discovery, %Types.NeighborDiscovery{} = nd}) do
|
||||
defp metric_to_tuple({:neighbor_discovery, %Types.NeighborDiscovery{} = nd}) do
|
||||
{
|
||||
:neighbor_discovery_metric,
|
||||
{
|
||||
|
|
@ -177,7 +177,7 @@ defmodule :towerops@proto@decode do
|
|||
def decode_agent_config(binary) when is_binary(binary) do
|
||||
case Decode.decode_agent_config(binary) do
|
||||
{:ok, %Types.AgentConfig{} = ac} ->
|
||||
# Convert devices and checks to Gleam tuples (not implemented yet, return empty lists)
|
||||
# Convert devices and checks to tuples (not implemented yet, return empty lists)
|
||||
{:ok, {:agent_config, ac.version, ac.poll_interval_seconds, [], []}}
|
||||
|
||||
{:error, reason} ->
|
||||
|
|
@ -189,7 +189,7 @@ defmodule :towerops@proto@decode do
|
|||
case Decode.decode_agent_job(binary) do
|
||||
{:ok, %Types.AgentJob{} = job} ->
|
||||
agent_job = types_job_to_agent_job(job)
|
||||
{:ok, Towerops.Proto.Agent.job_to_gleam(agent_job)}
|
||||
{:ok, Towerops.Proto.Agent.job_to_tuple(agent_job)}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
|
@ -199,10 +199,10 @@ defmodule :towerops@proto@decode do
|
|||
def decode_agent_job_list(binary) when is_binary(binary) do
|
||||
case Decode.decode_agent_job_list(binary) do
|
||||
{:ok, %Types.AgentJobList{jobs: jobs}} ->
|
||||
# Convert Types.AgentJob to Agent.AgentJob, then to Gleam tuples
|
||||
# Convert Types.AgentJob to Agent.AgentJob, then to tuples
|
||||
agent_jobs = Enum.map(jobs, &types_job_to_agent_job/1)
|
||||
gleam_jobs = Enum.map(agent_jobs, &Towerops.Proto.Agent.job_to_gleam/1)
|
||||
{:ok, {:agent_job_list, gleam_jobs}}
|
||||
tuple_jobs = Enum.map(agent_jobs, &Towerops.Proto.Agent.job_to_tuple/1)
|
||||
{:ok, {:agent_job_list, tuple_jobs}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
|
@ -266,13 +266,13 @@ defmodule :towerops@proto@decode do
|
|||
def decode_lldp_topology_result(binary) when is_binary(binary) do
|
||||
case Decode.decode_lldp_topology_result(binary) do
|
||||
{:ok, %Types.LldpTopologyResult{} = ltr} ->
|
||||
# Convert LldpNeighbor structs to Gleam tuples
|
||||
gleam_neighbors =
|
||||
# Convert LldpNeighbor structs to tuples
|
||||
tuple_neighbors =
|
||||
Enum.map(ltr.neighbors, fn %Types.LldpNeighbor{} = n ->
|
||||
{:lldp_neighbor, n.neighbor_name, n.local_port, n.remote_port, n.remote_port_id, n.management_addresses}
|
||||
end)
|
||||
|
||||
{:ok, {:lldp_topology_result, ltr.device_id, ltr.job_id, ltr.local_system_name, gleam_neighbors, ltr.timestamp}}
|
||||
{:ok, {:lldp_topology_result, ltr.device_id, ltr.job_id, ltr.local_system_name, tuple_neighbors, ltr.timestamp}}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
defmodule :towerops@proto@encode do
|
||||
defmodule Towerops.Proto.TupleEncode do
|
||||
@moduledoc """
|
||||
Erlang compatibility wrapper for encoding protobuf messages.
|
||||
Accepts Gleam-style tuples and converts them to Elixir structs for encoding.
|
||||
Compatibility wrapper for encoding protobuf messages.
|
||||
Accepts tagged tuples and converts them to Elixir structs for encoding.
|
||||
"""
|
||||
|
||||
alias Towerops.Proto.Encode
|
||||
|
|
@ -102,8 +102,8 @@ defmodule :towerops@proto@encode do
|
|||
|
||||
# AgentConfig
|
||||
def encode_agent_config({:agent_config, version, poll_interval, devices, checks}) do
|
||||
device_structs = Enum.map(devices, &gleam_device_to_types/1)
|
||||
check_structs = Enum.map(checks, &gleam_check_to_types/1)
|
||||
device_structs = Enum.map(devices, &tuple_device_to_types/1)
|
||||
check_structs = Enum.map(checks, &tuple_check_to_types/1)
|
||||
|
||||
Encode.encode_agent_config(%Types.AgentConfig{
|
||||
version: version,
|
||||
|
|
@ -171,9 +171,9 @@ defmodule :towerops@proto@encode do
|
|||
end
|
||||
|
||||
# Metric
|
||||
def encode_metric(gleam_metric) do
|
||||
def encode_metric(tuple_metric) do
|
||||
metric_struct =
|
||||
case gleam_metric do
|
||||
case tuple_metric do
|
||||
{:sensor_reading_metric, {:sensor_reading, sensor_id, value, status, timestamp}} ->
|
||||
{:sensor_reading,
|
||||
%Types.SensorReading{
|
||||
|
|
@ -240,8 +240,8 @@ defmodule :towerops@proto@encode do
|
|||
end
|
||||
|
||||
# MetricBatch
|
||||
def encode_metric_batch({:metric_batch, gleam_metrics}) do
|
||||
metric_structs = Enum.map(gleam_metrics, &gleam_metric_to_types/1)
|
||||
def encode_metric_batch({:metric_batch, tuple_metrics}) do
|
||||
metric_structs = Enum.map(tuple_metrics, &tuple_metric_to_types/1)
|
||||
Encode.encode_metric_batch(%Types.MetricBatch{metrics: metric_structs})
|
||||
end
|
||||
|
||||
|
|
@ -257,8 +257,8 @@ defmodule :towerops@proto@encode do
|
|||
end
|
||||
|
||||
# CheckList
|
||||
def encode_check_list({:check_list, gleam_checks}) do
|
||||
check_structs = Enum.map(gleam_checks, &gleam_check_to_types/1)
|
||||
def encode_check_list({:check_list, tuple_checks}) do
|
||||
check_structs = Enum.map(tuple_checks, &tuple_check_to_types/1)
|
||||
Encode.encode_check_list(%Types.CheckList{checks: check_structs})
|
||||
end
|
||||
|
||||
|
|
@ -291,14 +291,14 @@ defmodule :towerops@proto@encode do
|
|||
end
|
||||
|
||||
# AgentJobList
|
||||
def encode_agent_job_list({:agent_job_list, gleam_jobs}) do
|
||||
job_structs = Enum.map(gleam_jobs, &gleam_job_to_types/1)
|
||||
def encode_agent_job_list({:agent_job_list, tuple_jobs}) do
|
||||
job_structs = Enum.map(tuple_jobs, &tuple_job_to_types/1)
|
||||
Encode.encode_agent_job_list(%Types.AgentJobList{jobs: job_structs})
|
||||
end
|
||||
|
||||
# AgentJob
|
||||
def encode_agent_job(gleam_job) do
|
||||
job_struct = gleam_job_to_types(gleam_job)
|
||||
def encode_agent_job(tuple_job) do
|
||||
job_struct = tuple_job_to_types(tuple_job)
|
||||
Encode.encode_agent_job(job_struct)
|
||||
end
|
||||
|
||||
|
|
@ -343,8 +343,8 @@ defmodule :towerops@proto@encode do
|
|||
|
||||
# Helper functions for complex conversions
|
||||
|
||||
defp gleam_metric_to_types(gleam_metric) do
|
||||
case gleam_metric do
|
||||
defp tuple_metric_to_types(tuple_metric) do
|
||||
case tuple_metric do
|
||||
{:sensor_reading_metric, {:sensor_reading, sensor_id, value, status, timestamp}} ->
|
||||
{:sensor_reading,
|
||||
%Types.SensorReading{
|
||||
|
|
@ -389,7 +389,7 @@ defmodule :towerops@proto@encode do
|
|||
end
|
||||
end
|
||||
|
||||
defp gleam_check_to_types({:check, id, check_type, interval_seconds, timeout_ms, config}) do
|
||||
defp tuple_check_to_types({:check, id, check_type, interval_seconds, timeout_ms, config}) do
|
||||
config_struct =
|
||||
case config do
|
||||
{:http_config,
|
||||
|
|
@ -434,12 +434,12 @@ defmodule :towerops@proto@encode do
|
|||
}
|
||||
end
|
||||
|
||||
defp gleam_device_to_types(gleam_device) do
|
||||
defp tuple_device_to_types(tuple_device) do
|
||||
# Stub - implement if needed
|
||||
gleam_device
|
||||
tuple_device
|
||||
end
|
||||
|
||||
defp gleam_job_to_types(
|
||||
defp tuple_job_to_types(
|
||||
{:agent_job, job_id, job_type, device_id, snmp_device, queries, mikrotik_device, mikrotik_commands}
|
||||
) do
|
||||
snmp_device_struct =
|
||||
|
|
@ -6,7 +6,7 @@ defmodule Towerops.Snmp.SensorChangeDetector do
|
|||
event detection across both Phoenix-polled and agent-polled devices.
|
||||
|
||||
Pure decision logic (threshold checking, value formatting) is implemented
|
||||
in Gleam. PubSub broadcasting, Repo queries, and event building stay here.
|
||||
as helper functions. PubSub broadcasting, Repo queries, and event building stay here.
|
||||
"""
|
||||
|
||||
alias Towerops.Snmp.Sensor
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ defmodule ToweropsWeb.ChangelogParser do
|
|||
|
||||
@doc """
|
||||
Parse changelog content string into a list of entries.
|
||||
Returns tuples in Gleam format: {:changelog_entry, date, title_opt, items}
|
||||
Returns internal tuples: {:changelog_entry, date, title_opt, items}
|
||||
"""
|
||||
def parse_content(content) when is_binary(content) do
|
||||
content
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
stdenv,
|
||||
mkShell,
|
||||
writeShellScriptBin,
|
||||
# Elixir/Erlang/Gleam
|
||||
# Elixir/Erlang
|
||||
elixir,
|
||||
gleam,
|
||||
# Databases and caches
|
||||
postgresql_16,
|
||||
redis,
|
||||
|
|
@ -217,9 +216,8 @@ mkShell {
|
|||
|
||||
# Development tools
|
||||
buildInputs = [
|
||||
# Elixir/Erlang/Gleam
|
||||
# Elixir/Erlang
|
||||
elixir
|
||||
gleam
|
||||
|
||||
# Databases (PostgreSQL with TimescaleDB)
|
||||
pg
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ defmodule Towerops.Agent.ProtoTest do
|
|||
Tests for Protocol Buffer generated modules.
|
||||
|
||||
These tests verify that encoding and decoding works correctly for all
|
||||
protobuf message types used in agent communication. The Gleam-based
|
||||
protobuf message types used in agent communication. The
|
||||
implementation uses {:ok, struct} tuples for decode where available,
|
||||
and some modules are encode-only.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
defmodule ToweropsWeb.GleamChangelogParserTest do
|
||||
defmodule ToweropsWeb.ChangelogParserTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias ToweropsWeb.ChangelogParser
|
||||
Loading…
Add table
Reference in a new issue