- SIPGateway field in NodeMetric model - HasNode() engine method - OnNewNode callback in NATS subscriber - Auto-create balance trunk from new node metric - BroadcastGatewayEvent on WS hub - Gateway status indicators in trunks UI (green/red/gray) - SPA fallback for frontend routing
219 lines
7.3 KiB
Go
219 lines
7.3 KiB
Go
// Package models содержит общие типы данных pulse-lets-go.
|
||
package models
|
||
|
||
import "time"
|
||
|
||
// --- NATS: метрика от нижестоящей АТС ---
|
||
|
||
// NodeMetric — сообщение, публикуемое нодой в NATS каждые 5 сек.
|
||
type NodeMetric struct {
|
||
NodeID string `json:"node_id"`
|
||
TS int64 `json:"ts"` // unix timestamp
|
||
Status string `json:"status"` // "ok", "degraded", "down"
|
||
ActiveCalls int `json:"active_calls"`
|
||
MaxCalls int `json:"max_calls"`
|
||
IdleCPU float64 `json:"idle_cpu"` // 0..100 %
|
||
LoadAvg float64 `json:"load_avg"` // system load average (1m)
|
||
CallFailureRate float64 `json:"call_failure_rate"` // 0.0..100.0 %
|
||
SIPGateway string `json:"sip_gateway,omitempty"` // SIP-адрес ноды для авто-создания транка
|
||
}
|
||
|
||
// --- In-memory состояние ноды в engine ---
|
||
|
||
// NodeState — полное состояние ноды в памяти балансировщика.
|
||
// Содержит данные последней метрики + поля ручного управления.
|
||
type NodeState struct {
|
||
NodeMetric
|
||
Disabled bool `json:"disabled"`
|
||
DisabledReason string `json:"disabled_reason"`
|
||
Score float64 `json:"score"`
|
||
LethalReason string `json:"lethal_reason,omitempty"` // причина, если score = -100
|
||
}
|
||
|
||
// --- Trunk ---
|
||
|
||
// TrunkType — тип транка.
|
||
type TrunkType string
|
||
|
||
const (
|
||
TrunkIngress TrunkType = "ingress"
|
||
TrunkBalance TrunkType = "balance"
|
||
TrunkFallback TrunkType = "fallback"
|
||
)
|
||
|
||
// Trunk — модель транка (из trunks.json).
|
||
type Trunk struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Type TrunkType `json:"type"`
|
||
NodeID string `json:"node_id,omitempty"` // только для balance
|
||
Gateway string `json:"gateway"`
|
||
Codecs []string `json:"codecs,omitempty"`
|
||
Context string `json:"context,omitempty"`
|
||
Enabled bool `json:"enabled"`
|
||
Description string `json:"description,omitempty"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// --- User ---
|
||
|
||
// UserRole — роль пользователя.
|
||
type UserRole string
|
||
|
||
const (
|
||
RoleAdmin UserRole = "admin"
|
||
RoleViewer UserRole = "viewer"
|
||
)
|
||
|
||
// User — модель пользователя (из users.json).
|
||
type User struct {
|
||
ID string `json:"id"`
|
||
Username string `json:"username"`
|
||
PasswordHash string `json:"password_hash"`
|
||
Role UserRole `json:"role"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// --- Auth ---
|
||
|
||
// LoginRequest — тело запроса на /api/auth/login.
|
||
type LoginRequest struct {
|
||
Username string `json:"username"`
|
||
Password string `json:"password"`
|
||
}
|
||
|
||
// LoginResponse — тело ответа /api/auth/login.
|
||
type LoginResponse struct {
|
||
AccessToken string `json:"access_token"`
|
||
RefreshToken string `json:"refresh_token"`
|
||
ExpiresIn int64 `json:"expires_in"`
|
||
}
|
||
|
||
// --- /api/route ---
|
||
|
||
// RouteResponse — ответ на запрос маршрутизации.
|
||
type RouteResponse struct {
|
||
// Успех
|
||
NodeID string `json:"node_id,omitempty"`
|
||
Score float64 `json:"score,omitempty"`
|
||
SIPGateway string `json:"sip_gateway,omitempty"`
|
||
|
||
// Fallback
|
||
Fallback bool `json:"fallback,omitempty"`
|
||
Reason string `json:"reason,omitempty"`
|
||
|
||
// Общая информация о нодах
|
||
Nodes []RouteNodeInfo `json:"nodes,omitempty"`
|
||
|
||
// Ошибка
|
||
Error string `json:"error,omitempty"`
|
||
}
|
||
|
||
// RouteNodeInfo — информация о ноде в ответе маршрутизации.
|
||
type RouteNodeInfo struct {
|
||
ID string `json:"id"`
|
||
Score float64 `json:"score"`
|
||
Reason string `json:"reason,omitempty"`
|
||
Status string `json:"status"`
|
||
}
|
||
|
||
// --- API: Nodes ---
|
||
|
||
// ToggleNodeRequest — запрос на включение/выключение ноды.
|
||
type ToggleNodeRequest struct {
|
||
Disabled bool `json:"disabled"`
|
||
Reason string `json:"reason,omitempty"`
|
||
}
|
||
|
||
// NodeInfo — информация о ноде для фронта.
|
||
type NodeInfo struct {
|
||
NodeID string `json:"node_id"`
|
||
TS int64 `json:"ts"`
|
||
Status string `json:"status"`
|
||
ActiveCalls int `json:"active_calls"`
|
||
MaxCalls int `json:"max_calls"`
|
||
IdleCPU float64 `json:"idle_cpu"`
|
||
LoadAvg float64 `json:"load_avg"`
|
||
CallFailureRate float64 `json:"call_failure_rate"`
|
||
Disabled bool `json:"disabled"`
|
||
DisabledReason string `json:"disabled_reason,omitempty"`
|
||
Score float64 `json:"score"`
|
||
LethalReason string `json:"lethal_reason,omitempty"`
|
||
IsStale bool `json:"is_stale"`
|
||
SecondsAgo float64 `json:"seconds_ago"`
|
||
}
|
||
|
||
// --- API: Users ---
|
||
|
||
// CreateUserRequest — запрос на создание пользователя.
|
||
type CreateUserRequest struct {
|
||
Username string `json:"username"`
|
||
Password string `json:"password"`
|
||
Role UserRole `json:"role"`
|
||
}
|
||
|
||
// UpdateUserRequest — запрос на обновление пользователя.
|
||
type UpdateUserRequest struct {
|
||
Username *string `json:"username,omitempty"`
|
||
Password *string `json:"password,omitempty"`
|
||
Role *UserRole `json:"role,omitempty"`
|
||
}
|
||
|
||
// --- API: Trunks ---
|
||
|
||
// CreateTrunkRequest — запрос на создание транка.
|
||
type CreateTrunkRequest struct {
|
||
Name string `json:"name"`
|
||
Type TrunkType `json:"type"`
|
||
NodeID string `json:"node_id,omitempty"`
|
||
Gateway string `json:"gateway"`
|
||
Codecs []string `json:"codecs,omitempty"`
|
||
Context string `json:"context,omitempty"`
|
||
Enabled bool `json:"enabled"`
|
||
Description string `json:"description,omitempty"`
|
||
}
|
||
|
||
// UpdateTrunkRequest — запрос на обновление транка.
|
||
type UpdateTrunkRequest struct {
|
||
Name *string `json:"name,omitempty"`
|
||
Type *TrunkType `json:"type,omitempty"`
|
||
NodeID *string `json:"node_id,omitempty"`
|
||
Gateway *string `json:"gateway,omitempty"`
|
||
Codecs []string `json:"codecs,omitempty"`
|
||
Context *string `json:"context,omitempty"`
|
||
Enabled *bool `json:"enabled,omitempty"`
|
||
Description *string `json:"description,omitempty"`
|
||
}
|
||
|
||
// --- Monitoring ---
|
||
|
||
// ZabbixNode — элемент LLD (Low-Level Discovery) для Zabbix.
|
||
type ZabbixNode struct {
|
||
NodeID string `json:"{#NODE_ID}"`
|
||
Status string `json:"{#STATUS}"`
|
||
ActiveCalls int `json:"{#ACTIVE_CALLS}"`
|
||
MaxCalls int `json:"{#MAX_CALLS}"`
|
||
IdleCPU float64 `json:"{#IDLE_CPU}"`
|
||
LoadAvg float64 `json:"{#LOAD_AVG}"`
|
||
CallFailureRate float64 `json:"{#CALL_FAILURE_RATE}"`
|
||
Score float64 `json:"{#SCORE}"`
|
||
Disabled bool `json:"{#DISABLED}"`
|
||
IsStale bool `json:"{#IS_STALE}"`
|
||
SecondsAgo float64 `json:"{#SECONDS_AGO}"`
|
||
}
|
||
|
||
// ZabbixResponse — ответ на запрос Zabbix LLD.
|
||
type ZabbixResponse struct {
|
||
Data []ZabbixNode `json:"data"`
|
||
}
|
||
|
||
// --- WebSocket ---
|
||
|
||
// WsMetricsMessage — сообщение, отправляемое по WebSocket.
|
||
type WsMetricsMessage struct {
|
||
Type string `json:"type"` // "nodes_update", "node_toggle", etc
|
||
Payload interface{} `json:"payload"`
|
||
}
|