105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package api
|
||
|
||
import (
|
||
"net/http"
|
||
|
||
"github.com/pulse-lets-go/internal/models"
|
||
)
|
||
|
||
// handleRoute — GET /api/route — главный эндпоинт маршрутизации вызова.
|
||
func (a *API) handleRoute(w http.ResponseWriter, r *http.Request) {
|
||
a.engine.IncrementRouteRequests()
|
||
|
||
nodeID, score, fallback := a.engine.GetBestNode()
|
||
|
||
// Нет зарегистрированных нод
|
||
if nodeID == "" {
|
||
a.engine.IncrementRouteFallbacks()
|
||
writeJSON(w, http.StatusServiceUnavailable, models.RouteResponse{
|
||
Error: "no_nodes_registered",
|
||
})
|
||
return
|
||
}
|
||
|
||
// Все ноды unhealthy — fallback
|
||
if fallback || score < 0 {
|
||
a.engine.IncrementRouteFallbacks()
|
||
fallbackGW, _ := a.findFallbackGateway()
|
||
nodes := a.getRouteNodeInfo()
|
||
|
||
writeJSON(w, http.StatusOK, models.RouteResponse{
|
||
Fallback: true,
|
||
SIPGateway: fallbackGW,
|
||
Reason: "all_nodes_unhealthy",
|
||
Nodes: nodes,
|
||
})
|
||
return
|
||
}
|
||
|
||
// Нормальный маршрут
|
||
gw, ok := a.findBalanceGateway(nodeID)
|
||
if !ok {
|
||
writeError(w, http.StatusInternalServerError, "gateway не найден для ноды")
|
||
return
|
||
}
|
||
|
||
writeJSON(w, http.StatusOK, models.RouteResponse{
|
||
NodeID: nodeID,
|
||
Score: score,
|
||
SIPGateway: gw,
|
||
})
|
||
}
|
||
|
||
// findBalanceGateway ищет gateway для balance-транка, привязанного к nodeID.
|
||
func (a *API) findBalanceGateway(nodeID string) (string, bool) {
|
||
trunks, err := a.configManager.ReadTrunks()
|
||
if err != nil {
|
||
return "", false
|
||
}
|
||
for _, t := range trunks {
|
||
if t.Type == models.TrunkBalance && t.NodeID == nodeID && t.Enabled {
|
||
return t.Gateway, true
|
||
}
|
||
}
|
||
return "", false
|
||
}
|
||
|
||
// findFallbackGateway ищет gateway для fallback-транка.
|
||
func (a *API) findFallbackGateway() (string, bool) {
|
||
trunks, err := a.configManager.ReadTrunks()
|
||
if err != nil {
|
||
return "", false
|
||
}
|
||
for _, t := range trunks {
|
||
if t.Type == models.TrunkFallback && t.Enabled {
|
||
return t.Gateway, true
|
||
}
|
||
}
|
||
return "", false
|
||
}
|
||
|
||
// getRouteNodeInfo возвращает список нод с их скорами для ответа маршрутизации.
|
||
func (a *API) getRouteNodeInfo() []models.RouteNodeInfo {
|
||
nodes := a.engine.GetAllNodes()
|
||
result := make([]models.RouteNodeInfo, 0, len(nodes))
|
||
for _, n := range nodes {
|
||
info := models.RouteNodeInfo{
|
||
ID: n.NodeID,
|
||
Score: n.Score,
|
||
Reason: n.LethalReason,
|
||
Status: n.Status,
|
||
}
|
||
if n.Disabled {
|
||
info.Status = "disabled"
|
||
} else if n.IsStale {
|
||
info.Status = "stale"
|
||
} else if n.Score < 0 {
|
||
info.Status = "unhealthy"
|
||
} else {
|
||
info.Status = "healthy"
|
||
}
|
||
result = append(result, info)
|
||
}
|
||
return result
|
||
}
|