- add absinthe_phoenix for WebSocket subscription support - create GraphQL WebSocket socket with API token auth at /socket/graphql - add time-series queries: deviceSensors, sensorReadings, interfaceTraffic, checkResults - add subscriptions: deviceStatusChanged, alertEvent, sensorReadingsUpdated - wire subscription triggers into agent_channel and alerts contexts - add org-scoped access control for sensors/interfaces via join queries - add 17 tests covering queries, org isolation, empty data edge cases, and auth - update GraphQL API docs page with time-series and subscription sections
71 lines
1.9 KiB
Elixir
71 lines
1.9 KiB
Elixir
defmodule ToweropsWeb.GraphQL.Subscriptions do
|
|
@moduledoc """
|
|
Publishes events to GraphQL subscriptions.
|
|
|
|
Each function builds the subscription payload and calls
|
|
`Absinthe.Subscription.publish/3` to push to connected subscribers.
|
|
"""
|
|
|
|
@doc """
|
|
Publishes a device status change event.
|
|
|
|
Publishes to both org-wide and device-specific subscription topics.
|
|
"""
|
|
def publish_device_status(device_id, org_id, %{device_name: device_name, status: status}) do
|
|
payload = %{
|
|
device_id: device_id,
|
|
device_name: device_name,
|
|
status: status,
|
|
changed_at: to_string(DateTime.utc_now())
|
|
}
|
|
|
|
Absinthe.Subscription.publish(
|
|
ToweropsWeb.Endpoint,
|
|
payload,
|
|
device_status_changed: "gql:device_status:#{org_id}",
|
|
device_status_changed: "gql:device_status:#{org_id}:#{device_id}"
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Publishes an alert lifecycle event (created, acknowledged, resolved).
|
|
|
|
Accepts both Alert structs and plain maps.
|
|
"""
|
|
def publish_alert_event(alert, event_type) do
|
|
payload = %{
|
|
alert_id: Map.get(alert, :id),
|
|
alert_type: Map.get(alert, :alert_type),
|
|
severity: Map.get(alert, :severity),
|
|
message: Map.get(alert, :message),
|
|
device_id: Map.get(alert, :device_id),
|
|
event_type: event_type,
|
|
triggered_at: to_string(Map.get(alert, :triggered_at))
|
|
}
|
|
|
|
org_id = Map.get(alert, :organization_id)
|
|
|
|
Absinthe.Subscription.publish(
|
|
ToweropsWeb.Endpoint,
|
|
payload,
|
|
alert_event: "gql:alerts:#{org_id}"
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Publishes a batch of sensor readings for a device.
|
|
"""
|
|
def publish_sensor_readings(device_id, org_id, device_name, readings) do
|
|
payload = %{
|
|
device_id: device_id,
|
|
device_name: device_name,
|
|
readings: readings
|
|
}
|
|
|
|
Absinthe.Subscription.publish(
|
|
ToweropsWeb.Endpoint,
|
|
payload,
|
|
sensor_readings_updated: "gql:sensor_readings:#{org_id}:#{device_id}"
|
|
)
|
|
end
|
|
end
|