92 lines
2.7 KiB
Go
92 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 запускает основной цикл реконнекта и чтения событий.
|
||
// При успешном подключении:
|
||
// - Вызывает 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"
|
||
|
||
go func() {
|
||
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()
|
||
// Не ждём реконнект внутри 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)
|
||
}
|
||
}()
|
||
}
|