package esl import ( "fmt" "log" "strings" ) // GatewayAdd создаёт gateway на FreeSWITCH через Sofia профиль. // Возвращает nil если gateway создан или уже существует (идемпотентность). func (c *Client) GatewayAdd(profile, name, proxy string) error { cmd := fmt.Sprintf("api sofia profile %s gwadd %s %s", profile, name, proxy) headers, body, err := c.Send(cmd) c.IncGatewayOps() if err != nil { log.Printf("[esl] GatewayAdd %s: ошибка команды: %v", name, err) return err } reply := headers["Reply-Text"] if strings.HasPrefix(reply, "+OK") { log.Printf("[esl] GatewayAdd %s: создан (%s → %s)", name, profile, proxy) return nil } // Gateway уже существует — не ошибка if strings.Contains(body, "GATEWAY ALREADY") || strings.Contains(reply, "GATEWAY ALREADY") { log.Printf("[esl] GatewayAdd %s: уже существует, ок", name) return nil } log.Printf("[esl] GatewayAdd %s: ошибка FS — Reply: %s, Body: %s", name, reply, body) return fmt.Errorf("GatewayAdd %s: %s (%s)", name, reply, body) } // GatewayDelete удаляет gateway на FreeSWITCH. // Возвращает nil если gateway удалён или не найден (идемпотентность). func (c *Client) GatewayDelete(profile, name string) error { cmd := fmt.Sprintf("api sofia profile %s gwdel %s", profile, name) headers, body, err := c.Send(cmd) c.IncGatewayOps() if err != nil { log.Printf("[esl] GatewayDelete %s: ошибка команды: %v", name, err) return err } reply := headers["Reply-Text"] if strings.HasPrefix(reply, "+OK") { log.Printf("[esl] GatewayDelete %s: удалён", name) return nil } // Gateway не найден — не ошибка if strings.Contains(body, "GATEWAY NOT FOUND") || strings.Contains(reply, "GATEWAY NOT FOUND") { log.Printf("[esl] GatewayDelete %s: не найден, ок", name) return nil } log.Printf("[esl] GatewayDelete %s: ошибка FS — Reply: %s, Body: %s", name, reply, body) return fmt.Errorf("GatewayDelete %s: %s (%s)", name, reply, body) } // 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 }