Maksim Totmin 533a1fba49 feat: ESL client, gateway management, event subscription
- Raw TCP ESL client with reconnect
- GatewayAdd/GatewayDelete/GatewaySyncAll
- SOFIA::gateway_* event processing
- SendAsync for deadlock-free bgapi commands
2026-06-25 16:56:42 +07:00

78 lines
2.6 KiB
Go

package esl
import (
"fmt"
"log"
"strings"
)
// GatewayAdd создаёт gateway на FreeSWITCH через Sofia профиль.
// Использует bgapi — асинхронная команда, результат приходит как BACKGROUND_JOB событие.
func (c *Client) GatewayAdd(profile, name, proxy string) error {
cmd := fmt.Sprintf("bgapi sofia profile %s gwadd %s %s", profile, name, proxy)
if err := c.SendAsync(cmd); err != nil {
log.Printf("[esl] GatewayAdd %s: ошибка: %v", name, err)
return err
}
c.IncGatewayOps()
log.Printf("[esl] GatewayAdd %s: отправлен (%s → %s)", name, profile, proxy)
return nil
}
// GatewayDelete удаляет gateway на FreeSWITCH.
// Использует bgapi — асинхронная команда, результат приходит как BACKGROUND_JOB событие.
func (c *Client) GatewayDelete(profile, name string) error {
cmd := fmt.Sprintf("bgapi sofia profile %s gwdel %s", profile, name)
if err := c.SendAsync(cmd); err != nil {
log.Printf("[esl] GatewayDelete %s: ошибка: %v", name, err)
return err
}
c.IncGatewayOps()
log.Printf("[esl] GatewayDelete %s: отправлен", name)
return nil
}
// GatewayList возвращает список имён gateway в заданном профиле.
func (c *Client) GatewayList(profile string) ([]string, error) {
cmd := fmt.Sprintf("api sofia profile %s gwlist", profile)
_, body, err := c.Send(cmd)
if err != nil {
return nil, fmt.Errorf("GatewayList: %w", err)
}
// Парсим вывод gwlist — имена gateway на отдельных строках
lines := strings.Split(body, "\n")
var gateways []string
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "Name:") || strings.HasPrefix(line, "====") {
continue
}
// Ищем строки вида "pulse-ingress-xxxxx sip:..."
if strings.Contains(line, "pulse-") {
parts := strings.Fields(line)
if len(parts) > 0 {
gateways = append(gateways, parts[0])
}
}
}
return gateways, nil
}
// GatewaySyncAll синхронизирует все ingress-транки как gateway на FS.
// Вызывается после реконнекта.
func (c *Client) GatewaySyncAll(profile string, gateways []GatewaySpec) {
for _, g := range gateways {
if err := c.GatewayAdd(profile, g.Name, g.Proxy); err != nil {
log.Printf("[esl] GatewaySyncAll: ошибка %s: %v", g.Name, err)
}
}
}
// GatewaySpec описывает gateway для синхронизации.
type GatewaySpec struct {
Name string
Proxy string
}