- Raw TCP ESL client with reconnect - GatewayAdd/GatewayDelete/GatewaySyncAll - SOFIA::gateway_* event processing - SendAsync for deadlock-free bgapi commands
90 lines
2.7 KiB
Go
90 lines
2.7 KiB
Go
package esl
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
// EventHandler — callback для обработки событий ESL.
|
|
// Принимает имя события и заголовки, вызывается из readEventsLoop.
|
|
type EventHandler func(eventName string, headers map[string]string, body string)
|
|
|
|
// StartEventLoop запускает основной цикл реконнекта и чтения событий.
|
|
// Блокирует до тех пор, пока контекст не будет отменён (ctx.Done()).
|
|
// При успешном подключении:
|
|
// - Вызывает onConnect (например, для GatewaySyncAll)
|
|
// - Подписывается на события SOFIA::gateway_register/unregister
|
|
// - Запускает чтение асинхронных событий
|
|
// При разрыве соединения — автоматический реконнект.
|
|
func (c *Client) StartEventLoop(ctx context.Context, profile string, onConnect func(), onEvent EventHandler) {
|
|
const subscribeEvents = "SOFIA::gateway_register SOFIA::gateway_unregister SOFIA::gateway_expire"
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
c.Disconnect()
|
|
return
|
|
default:
|
|
}
|
|
|
|
// Пытаемся подключиться
|
|
log.Printf("[esl] попытка подключения к %s:%d", c.host, c.port)
|
|
if err := c.Connect(); err != nil {
|
|
log.Printf("[esl] ошибка подключения: %v, повтор через %v", err, c.backoff)
|
|
time.Sleep(c.backoff)
|
|
c.backoff *= 2
|
|
if c.backoff > 60*time.Second {
|
|
c.backoff = 60 * time.Second
|
|
}
|
|
continue
|
|
}
|
|
|
|
// Успешное подключение
|
|
c.backoff = 1 * time.Second
|
|
|
|
// Подписываемся на события
|
|
if err := c.Subscribe(subscribeEvents); err != nil {
|
|
log.Printf("[esl] ошибка подписки: %v", err)
|
|
c.Disconnect()
|
|
continue
|
|
}
|
|
|
|
// Вызываем callback (GatewaySyncAll)
|
|
if onConnect != nil {
|
|
onConnect()
|
|
}
|
|
|
|
// Читаем события пока соединение живо
|
|
readEvents := make(chan struct{})
|
|
go func() {
|
|
defer close(readEvents)
|
|
c.readEventsLoop()
|
|
}()
|
|
|
|
// Основной цикл обработки событий
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
c.Disconnect()
|
|
return
|
|
case <-readEvents:
|
|
// Соединение разорвалось — идём на реконнект
|
|
log.Printf("[esl] чтение событий остановлено")
|
|
goto reconnect
|
|
case evt, ok := <-c.Events():
|
|
if !ok {
|
|
goto reconnect
|
|
}
|
|
if onEvent != nil {
|
|
onEvent(evt.Name, evt.Headers, evt.Body)
|
|
}
|
|
}
|
|
}
|
|
|
|
reconnect:
|
|
c.Disconnect()
|
|
time.Sleep(c.backoff)
|
|
}
|
|
}
|