Skip to content

Repository files navigation

Yeastar ATS Proxy architecture

ATS Proxy

Адаптер событий и записей между Yeastar S-Series и ReMarked CRM.

CI Python 3.11+ Flask 3.x Docker ready Version 3.2 MIT License

Быстрый запуск · Архитектура · Эксплуатация · Диагностика · Участие в проекте · Безопасность · Лицензия

ATS Proxy принимает HTTP-события звонка, преобразует их в контракт CRM, скачивает запись через Yeastar Open API v2 и публикует стабильную ссылку record_link. Он полезен, когда АТС находится во внутренней сети, а CRM не поддерживает формат событий Yeastar напрямую.

Note

Основная цепочка проверена на длительно работающем production-развёртывании: события поступают в CRM, WAV сохраняются локально и отдаются через /download/<filename>. Push в этот репозиторий не обновляет production автоматически.

Как это работает

flowchart LR
    PBX["Yeastar S-Series"]
    Proxy["ATS Proxy"]
    CRM["ReMarked CRM"]
    Storage[("records/")]

    PBX -->|"HTTP events: Invite, CallStatus, NewCdr"| Proxy
    Proxy -->|"JSON: invite, answer, hangup, cdr"| CRM
    Proxy -->|"login, get_random, download"| PBX
    Proxy --> Storage
    CRM -->|"GET record_link"| Proxy
    Storage --> Proxy
Loading

После NewCdr сервис ждёт появления записи, получает одноразовый ключ через recording/get_random, скачивает WAV через recording/download и только затем отправляет итоговый CDR со ссылкой на файл. Если файл не появился после всех попыток, CDR всё равно отправляется, но с пустым record_link.

8088 является стандартным HTTPS-портом веб-интерфейса Yeastar, а не отдельным обязательным портом API. Open API использует протокол и порт, указанные в ats.url.

Подробная схема: docs/architecture.md.

Возможности

  • события invite, answer, hangup и cdr для ReMarked;
  • связь событий одного звонка по callid;
  • нормализация номеров Yeastar;
  • загрузка записей с повторными попытками;
  • безопасная раздача файлов через GET /download/<filename>;
  • автоматическое удаление устаревших записей;
  • повторные попытки доставки событий в CRM;
  • health-check и просмотр активных звонков;
  • маскирование токенов, паролей и одноразовых ключей в debug-логах.

Быстрый запуск

Требования: Docker с Compose либо Python 3.11+.

cp config.example.json config.json
docker compose up -d --build
curl http://127.0.0.1:9001/health

config.json содержит секреты и исключён из Git. Каталог records/ также не попадает в репозиторий.

Конфигурация

Основные параметры находятся в config.json:

Параметр Назначение
ats.url Внутренний base URL веб-интерфейса и Open API АТС
ats.api_version Версия API, обычно v2.0.0
ats.user / ats.password Учётные данные API; Yeastar может требовать MD5 пароля
ats.verify_tls Проверка сертификата при HTTPS; включайте с доверенным сертификатом
ats.download_attempts Максимальное число попыток получить запись
ats.download_retry_delay Пауза между попытками в секундах
network.local_port Порт приложения внутри контейнера
network.heartbeat_ip Адрес сервера, на который АТС отправляет HTTP events
network.heartbeat_port Порт сервера, доступный АТС для /webhook
network.external_domain_or_ip Адрес, доступный серверу CRM
network.external_port Внешний порт, добавляемый в record_link
crm.url / crm.token Endpoint и токен ReMarked
storage.path Каталог записей внутри контейнера
storage.cleanup_days Срок хранения записей

Разделение local_port, heartbeat_port и external_port важно, когда Docker или маршрутизатор публикует один внутренний порт под несколькими внешними портами.

Полный пример: config.example.json.

CRM payload

{
  "token": "crm-token",
  "caller": "998901234567",
  "callee": "1000",
  "direction": "in",
  "event": "cdr",
  "start_timestamp": 1767439729,
  "state": "answered",
  "duration": 120,
  "talk_diuration": 115,
  "record_link": "http://proxy.example.com:9001/download/recording.wav",
  "call_uuid": "1767439729.6402",
  "date_start": "2026-01-03 16:17:00",
  "wait_duration": 5
}

Поле talk_diuration содержит историческую опечатку намеренно: это часть существующего контракта ReMarked.

HTTP endpoints

Метод и путь Назначение
POST /webhook Приём HTTP events Yeastar
GET /download/<filename> Получение сохранённой записи
GET /health Состояние сервиса и подключения к АТС
GET /calls Активные звонки в памяти процесса

/calls содержит номера телефонов и не должен публиковаться для произвольных адресов. Внешний доступ к сервису рекомендуется ограничивать firewall-правилами или reverse proxy.

Проверка

python -m compileall -q app.py ats_client.py
python -m unittest discover -s tests -v

Локальный запуск без Docker:

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
ATS_PROXY_CONFIG=config.example.json python app.py

Для PowerShell переменная задаётся так:

$env:ATS_PROXY_CONFIG = "config.example.json"
python app.py

Эксплуатация

Работающий production-контейнер не обновляется автоматически после push в Git. Новая версия должна выкатываться отдельно, с резервной копией config.json и каталога записей.

Лицензия

Проект распространяется по лицензии MIT.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages