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) } }