litnimax / astconfman

Asterisk ConfBridge Manager
GNU Lesser General Public License v3.0
45 stars 36 forks source link

не происходит обновления по событиям AMI #73

Closed boyapavel closed 2 years ago

boyapavel commented 2 years ago

не происходит динамическое обновление каналов(каналы статично зеленые, хоть с отключенным микрофоном, хоть без) по событиям ConfbridgeTalking, и в логах конференц-комнаты нету записей по событиям ConfbridgeTalking, хотя по факту события ConfbridgeTalking есть. test

niaproxy commented 2 years ago

Привет Зеленым цветом помечены активные участники конференции, при добавлении приглашаемых участников через список контактов они будут отмечатся красным цветом до момента подключения.

Отключенный микрофон показан слева от номера или имени контакта.

По событиям AMI: В консоли астериска сделай команду manager show connected При включенном веб интерфейсе в списке должен быть пользователь указанный с файле config.py в параметре AMI_USER

boyapavel commented 2 years ago

По раскрашиванию цветом понял, спасибо.

Остался вопрос по AMI событиям ConfbridgeTalking Коннект есть: manager show connected Username IP Address Start Elapsed FileDes HttpCnt Read Write conf 127.0.0.1 1648052996 19 22 0 1073750015 00000 1 users connected.

niaproxy commented 2 years ago

wget на сервере астериска есть?

boyapavel commented 2 years ago

Да, стоит: dpkg -l | grep wget ii wget 1.21-1+deb11u1 amd64 retrieves files from the web

niaproxy commented 2 years ago

В файле views.py есть функция event_listener_talk она использует wget для передачи информации о говорящем в основное окно программы

os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_on/%(conf)s/%(num)s 2>/dev/null', conf=event.keys['Conference'], num=txt))

Попробуй запустить wget напрямую при подключенном абоненте 61315: wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_on/2325/61315

boyapavel commented 2 years ago

что-то качает: `wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_on/2325/61315 --2022-03-24 11:29:21-- http://localhost:5000/asterisk/get_talkers_on/2325/61315 Resolving localhost (localhost)... 127.0.0.1, ::1 Connecting to localhost (localhost)|127.0.0.1|:5000... connected. HTTP request sent, awaiting response... 200 OK Length: 2 [text/html] Saving to: ‘STDOUT’

2022-03-24 11:29:21 (10,6 KB/s) - written to stdout [2/2]`

Результатом этого действия появляется запись в логе конференции: test2

niaproxy commented 2 years ago

Он должен в терминал возвращать ОК если все правильно. В вебке полжен был появится глиф справа от подключенного абонента.

boyapavel commented 2 years ago

в терминале всё ок, но глифов на вебке не появляется(

niaproxy commented 2 years ago

Все правильно - глиф появится когда функция целиком отработает, уже сам забыл.

В таком случае не срабатывает тригер на событие AMI отсюда: client.add_event_listener

Я для примера давал в репозитории файл manager.conf - там среди прочего был фильтр по типу событий, как это настроено у тебя?

boyapavel commented 2 years ago

Да, фильтр выставил.

Более того, руками подключился к AMI, события валятся:

`Event: ConfbridgeTalking Privilege: call,all Conference: 2325 BridgeUniqueid: a83789bf-643a-48a4-a791-f29a1d98848c BridgeType: base BridgeTechnology: softmix BridgeCreator: ConfBridge BridgeName: 2325 BridgeNumChannels: 2 BridgeVideoSourceMode: none Channel: SIP/cucm-01-0000004e ChannelState: 6 ChannelStateDesc: Up CallerIDNum: 61315 CallerIDName: 61315 Pavel Boyarshinov ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: confman-bridge Exten: 2325 Priority: 5 Uniqueid: 1648122478.137 Linkedid: 1648122478.137 TalkingStatus: on Admin: No

Event: ConfbridgeTalking Privilege: call,all Conference: 2325 BridgeUniqueid: a83789bf-643a-48a4-a791-f29a1d98848c BridgeType: base BridgeTechnology: softmix BridgeCreator: ConfBridge BridgeName: 2325 BridgeNumChannels: 2 BridgeVideoSourceMode: none Channel: SIP/cucm-01-0000004e ChannelState: 6 ChannelStateDesc: Up CallerIDNum: 61315 CallerIDName: 61315 Pavel Boyarshinov ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: confman-bridge Exten: 2325 Priority: 5 Uniqueid: 1648122478.137 Linkedid: 1648122478.137 TalkingStatus: off Admin: No `

niaproxy commented 2 years ago

На всякий случай сделай в папке с исходниками git log | head актуальный коммит сверху должен быть 52f8736feabfb811d8808c58c51564802d473f54

boyapavel commented 2 years ago

у меня нету лог-файла, качал целиком с гитхаба, затем ложил на сервер с астериском...

niaproxy commented 2 years ago

Если ты скачал архив после 21 февраля все норм.

Вернемся к коду: https://github.com/litnimax/astconfman/blob/52f8736feabfb811d8808c58c51564802d473f54/astconfman/views.py#L1008

Я столкнулся с проблемой - астериск пишет в поле CallerIDNum символы пустой строки и SIP имена вместо цифр, это ломало парсер и останавливало отображение говорящих до перезапуска веб-приложения. if str(txt).isdigit(): - эта функция фильтрует только цифровые значения. Можешь попробовать закоментировать ее и сдвинуть идущие следом строки вровень с ней. Если все работает как надо в консоли должный появлятся надписи ОК каждый раз когда обнаружен голос.

Кстати какая версия астериска?

niaproxy commented 2 years ago

Вот еще что вспомнил:

Don't forget to enable talker detection events in participant profile settings and reload Asterisk config.

В настройках профиля участника есть галочка для событий AMI - проверь ее и перезайди в конференцию.

boyapavel commented 2 years ago

архив качал пару дней назад. астериск 13-ой версии certified ветки. галочка, стоит, иначе не было-бы сообщений в ami, а они есть, где-то выше их публиковал) сейчас буду пробовать комментировать фильтр.

niaproxy commented 2 years ago

Какой браузер открывает веб-интерфейс?

boyapavel commented 2 years ago

Строчки закомметировал в def event_listener_talk и def event_listener_stoptalk, отступы сдвинул. Код работает, не падает, но и эффекта тоже никакого, увы( Пробую одновременно через два браузера chrome и лису

niaproxy commented 2 years ago

Перезапусти программу - проведи полный цикл с подключением и разговором. Пришли вывод терминала сюда.

niaproxy commented 2 years ago
(env) [root@External-PBX astconfman]# pip list
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Package          Version
---------------- -------
alembic          0.8.6
asterisk-ami     0.1.6
Babel            2.9.1
blinker          1.4
click            7.1.2
dnspython        1.16.0
dominate         2.6.0
email-validator  1.1.3
Flask            0.12.4
Flask-Admin      1.3.0
Flask-BabelEx    0.9.4
Flask-Bootstrap  3.3.7.1
Flask-Login      0.5.0
Flask-Mail       0.9.1
Flask-Migrate    2.7.0
Flask-Principal  0.4.0
Flask-Script     2.0.6
Flask-Security   3.0.0
Flask-SQLAlchemy 2.5.1
Flask-WTF        0.14.3
gevent           1.2.2
greenlet         1.1.2
idna             2.10
itsdangerous     1.1.0
Jinja2           2.11.3
Mako             1.1.6
MarkupSafe       1.1.1
passlib          1.7.4
pip              20.3.4
python-crontab   2.6.0
python-dateutil  2.8.2
python-editor    1.0.4
pytz             2021.3
setuptools       44.1.1
six              1.16.0
speaklater       1.3
SQLAlchemy       1.2.0b3
transliterate    1.10.2
visitor          0.1.3
Werkzeug         0.11.10
wheel            0.36.2
WTForms          2.3.3

Это выгрузка версий пакетов питона с рабочего сервера - проверь со своим сервером, раньше уже было такое что новые версии ломали все.

boyapavel commented 2 years ago

Строчки закомметировал в def event_listener_talk и def event_listener_stoptalk, отступы сдвинул. Код работает, не падает, но и эффекта тоже никакого, увы( Пробую одновременно через два браузера chrome и лису

boyapavel commented 2 years ago

случайно закрыл тикет. Нашел различия в версиях следующих пакетов: pytz 2022.1 wheel 0.37.1

Это может как-то влиять?

Перезапущу чуть позже. Логи run.py ? Самого астера нужны логи? Какой глубины?

boyapavel commented 2 years ago

поставил правильные версии пакетов.

перезапустил run.py, повторил процедуру захода в конференц-комнату с включение/отключением микрофонов, разговорами и детектированием речи.

Вывод в консоль:

(env) root@tmn1-ap35:/home/localadmin/astconfman/astconfman# ./run.py /home/localadmin/astconfman/env/lib/python2.7/site-packages/flasksqlalchemy/__init_\.py:873: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning. 'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and ' /home/localadmin/astconfman/env/lib/python2.7/site-packages/flask_admin/model/base.py:1139: UserWarning: Fields missing from ruleset: participants,logs warnings.warn(text) /home/localadmin/astconfman/env/lib/python2.7/site-packages/flask_admin/model/base.py:1139: UserWarning: Fields missing from ruleset: participants,user,logs warnings.warn(text) /home/localadmin/astconfman/env/lib/python2.7/site-packages/flask_admin/model/base.py:1139: UserWarning: Fields missing from ruleset: user warnings.warn(text) 10.19.48.145 - - [2022-03-25 03:49:16] "GET /admin/conference/details/?url=%2Fadmin%2Fconference%2F&id=2 HTTP/1.1" 200 18046 0.284196 10.19.48.145 - - [2022-03-25 03:49:16] "GET /asterisk/onlineparticipants.json/2325?\=1648180188185 HTTP/1.1" 200 109 0.020488 127.0.0.1 - - [2022-03-25 03:49:30] "GET /asterisk/checkconf/2325/61315 HTTP/1.1" 200 117 0.006147 127.0.0.1 - - [2022-03-25 03:49:30] "GET /asterisk/confprofile/2325 HTTP/1.1" 200 149 0.007893 127.0.0.1 - - [2022-03-25 03:49:30] "GET /asterisk/userprofile/2325/61315 HTTP/1.1" 200 280 0.012589 127.0.0.1 - - [2022-03-25 03:49:30] "GET /asterisk/enter_conference/2325/61315 HTTP/1.1" 200 117 0.012250 10.19.48.145 - - [2022-03-25 03:49:31] "GET /asterisk/onlineparticipants.json/2325?\=1648180188186 HTTP/1.1" 200 109 0.018562 127.0.0.1 - - [2022-03-25 03:51:54] "GET /asterisk/checkconf/2325/63354 HTTP/1.1" 200 117 0.007938 127.0.0.1 - - [2022-03-25 03:51:54] "GET /asterisk/confprofile/2325 HTTP/1.1" 200 149 0.005204 127.0.0.1 - - [2022-03-25 03:51:54] "GET /asterisk/userprofile/2325/63354 HTTP/1.1" 200 280 0.007455 127.0.0.1 - - [2022-03-25 03:51:54] "GET /asterisk/enter_conference/2325/63354 HTTP/1.1" 200 117 0.010895 10.19.48.145 - - [2022-03-25 03:51:54] "GET /sse_subscribe HTTP/1.1" 200 312 164.081666 10.19.48.145 - - [2022-03-25 03:51:55] "GET /asterisk/onlineparticipants.json/2325?\=1648180188187 HTTP/1.1" 200 281 0.022235 127.0.0.1 - - [2022-03-25 03:52:23] "GET /asterisk/leave_conference/2325/61315 HTTP/1.1" 200 117 0.011797 10.19.48.145 - - [2022-03-25 03:52:24] "GET /asterisk/onlineparticipants.json/2325?\=1648180188188 HTTP/1.1" 200 282 0.020935 127.0.0.1 - - [2022-03-25 03:52:26] "GET /asterisk/leave_conference/2325/63354 HTTP/1.1" 200 117 0.011238 10.19.48.145 - - [2022-03-25 03:52:28] "GET /asterisk/onlineparticipants.json/2325?\=1648180188189 HTTP/1.1" 200 109 0.018131 ^CKeyboardInterrupt Fri Mar 25 03:52:46 2022 Traceback (most recent call last): File "./run.py", line 11, in server.serve_forever() File "/home/localadmin/astconfman/env/lib/python2.7/site-packages/gevent/baseserver.py", line 362, in serve_forever self._stop_event.wait() File "/home/localadmin/astconfman/env/lib/python2.7/site-packages/gevent/event.py", line 219, in wait return self._wait(timeout) File "/home/localadmin/astconfman/env/lib/python2.7/site-packages/gevent/event.py", line 129, in _wait gotit = self._wait_core(timeout) File "/home/localadmin/astconfman/env/lib/python2.7/site-packages/gevent/event.py", line 106, in _wait_core result = self.hub.switch() File "/home/localadmin/astconfman/env/lib/python2.7/site-packages/gevent/hub.py", line 630, in switch return RawGreenlet.switch(self) KeyboardInterrupt (env) root@tmn1-ap35:/home/localadmin/astconfman/astconfman#

Браузер chrome, событий детектирования речи нету даже в логе( test3

niaproxy commented 2 years ago

Конференция 2325 создана только в веб-интерфейсе или продублирована в конфиге астериска?

Для понимания: я создаю номер конференции через веб и затем пишу в конфиге астериска этот номер указывающим на контекст confman-dialin - таким образом конфу создает непосредственно веб-интерфейс при первом подключении.

boyapavel commented 2 years ago

конференция создана только в вебе, вызовы попадают в неё через экстеншн confman-dialin,s,1

niaproxy commented 2 years ago

Поступим следующим образом: md5.txt Контрольные суммы файлов из репозитория сверить с твоей папкой командой: md5sum --quiet -c md5.txt

Затем если все файлы в норме займемся отладкой: в файл views.py в функцию event_listener_talk в начале добавить строку print(event.keys['CallerIDNum'],"talk") при разговоре в терминале должен появится текст с номером телефона. Если текста нет дальше исследуем работу AMI.

niaproxy commented 2 years ago

Раскопал в архивах прототип обработчика AMI

import os
import time
#from settings import login, connection
from asterisk2.ami import AMIClient
#from asterisk.ami import AutoReconnect
client = AMIClient(address='127.0.0.1',port=5038)
client.login(username='admin',secret='7890ec8ff2955ec70a1b390b62f023da')
from asterisk2.ami import EventListener

talkers = []

def event_listener(event,**kwargs):
    print(event.keys['CallerIDNum'],"talk")
    txt = event.keys['CallerIDNum']
#    talkers.append([int(s) for s in txt.split() if s.isdigit()])
def event_listener2(event,**kwargs):
    print(event.keys['CallerIDNum'],"donttalk")
    txt = event.keys['CallerIDNum']
#    talkers.remove([int(s) for s in txt.split() if s.isdigit()])
#    print('ConfbridgeTalking',event)

client.add_event_listener(
    on_event=event_listener,
    white_list='ConfbridgeTalking',
#    Conference='26098',
    TalkingStatus='on',
)

client.add_event_listener(
    on_event=event_listener2,
    white_list='ConfbridgeTalking',
#    Conference='26098',
    TalkingStatus='off',
)

#AutoReconnect(client)
try:
    while True:
      time.sleep(1)
except (KeyboardInterrupt, SystemExit):
    client.logoff()

Измени имя пользователя и пароль. Запускай его через тот-же virt-env что основную программу в параллельном режиме. Если все правильно - в терминале будет текст с номером говорящего

niaproxy commented 2 years ago

Как вариант можно создать конференцию напрямую через астериск и подключится через скрипт - проверить что события от астериска правильно обрабатываются.

boyapavel commented 2 years ago

добавил в функцию event_listener_talk строку print(event.keys['CallerIDNum'],"talk")

Эффекта ноль.

запустил обработчик AMI - выхлопа ноль. При этом в консоли астериска видны оба коннекта обработчиков AMI: tmn1-ap35*CLI> manager show connected Username IP Address Start Elapsed FileDes HttpCnt Read Write conf 127.0.0.1 1648438731 256 25 0 1073750015 00000 conf 127.0.0.1 1648438935 52 29 0 1073750015 00000 2 users connected.

boyapavel commented 2 years ago

на всякий случай скачал весь архив повторно, накатил по новой, но детектирования событий ami по прежнему нету(

niaproxy commented 2 years ago

Расскажи как ты получал выдачу AMI события из своего сообщения. В virt-env запусти python --version В iptables -L -n есть что-то про локалхост или tcp на 0.0.0.0 ?

boyapavel commented 2 years ago

подключился телнетом на порт 5038, далее action: login и т.д.

Python 2.7.18

iptables даже не стоят, сервер изолирован от внешних подключений.

boyapavel commented 2 years ago

Вот, прямо сейчас подключился телнетом к AMI, результат: Asterisk Call Manager/2.10.4

Response: Error Message: Missing action in request

Action: Login Username: conf Secret: 7890ec8ff2955ec70a1b390b62f023da

Response: Success Message: Authentication accepted

Event: FullyBooted Privilege: system,all Status: Fully Booted

Event: ConfbridgeTalking Privilege: call,all Conference: 2325 BridgeUniqueid: 097d72c4-ba81-4d7a-a5d7-93cc7a679f41 BridgeType: base BridgeTechnology: softmix BridgeCreator: ConfBridge BridgeName: 2325 BridgeNumChannels: 2 BridgeVideoSourceMode: none Channel: SIP/cucm-01-000000c4 ChannelState: 6 ChannelStateDesc: Up CallerIDNum: 61315 CallerIDName: 61315 Pavel Boyarshinov ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: confman-bridge Exten: 2325 Priority: 5 Uniqueid: 1648444550.332 Linkedid: 1648444550.332 TalkingStatus: on Admin: No

Event: ConfbridgeTalking Privilege: call,all Conference: 2325 BridgeUniqueid: 097d72c4-ba81-4d7a-a5d7-93cc7a679f41 BridgeType: base BridgeTechnology: softmix BridgeCreator: ConfBridge BridgeName: 2325 BridgeNumChannels: 2 BridgeVideoSourceMode: none Channel: SIP/cucm-01-000000c4 ChannelState: 6 ChannelStateDesc: Up CallerIDNum: 61315 CallerIDName: 61315 Pavel Boyarshinov ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: confman-bridge Exten: 2325 Priority: 5 Uniqueid: 1648444550.332 Linkedid: 1648444550.332 TalkingStatus: off Admin: No

Event: ConfbridgeTalking Privilege: call,all Conference: 2325 BridgeUniqueid: 097d72c4-ba81-4d7a-a5d7-93cc7a679f41 BridgeType: base BridgeTechnology: softmix BridgeCreator: ConfBridge BridgeName: 2325 BridgeNumChannels: 2 BridgeVideoSourceMode: none Channel: SIP/cucm-01-000000c4 ChannelState: 6 ChannelStateDesc: Up CallerIDNum: 61315 CallerIDName: 61315 Pavel Boyarshinov ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: confman-bridge Exten: 2325 Priority: 5 Uniqueid: 1648444550.332 Linkedid: 1648444550.332 TalkingStatus: on Admin: No

Event: ConfbridgeTalking Privilege: call,all Conference: 2325 BridgeUniqueid: 097d72c4-ba81-4d7a-a5d7-93cc7a679f41 BridgeType: base BridgeTechnology: softmix BridgeCreator: ConfBridge BridgeName: 2325 BridgeNumChannels: 2 BridgeVideoSourceMode: none Channel: SIP/cucm-01-000000c4 ChannelState: 6 ChannelStateDesc: Up CallerIDNum: 61315 CallerIDName: 61315 Pavel Boyarshinov ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: confman-bridge Exten: 2325 Priority: 5 Uniqueid: 1648444550.332 Linkedid: 1648444550.332 TalkingStatus: off Admin: No

boyapavel commented 2 years ago

Получается, что питон коннектится к AMI, но не отлавливает события из него (

niaproxy commented 2 years ago

Получается, что питон коннектится к AMI, но не отлавливает события из него (

Из всего спектра возможных несправностей пришли к одной - модуль asterisk-ami. Попробуй следующее:

cd ~
mkdir test-env 
virtualenv test-env
source test-env/bin/activate
pip2 install asterisk-ami

Затем исправь название модуля в тестовом скрипте с asterisk2 на asterisk и запусти. Кстати - через телнет поключение к localhost проходит без задержек?

boyapavel commented 2 years ago

запустил, коннект к ami есть, выхлопа по прежнему нету(

niaproxy commented 2 years ago

Вот скрипт который должен выдавать в териминал все события подряд, незабудь поменять пароль и названия модуля при необходимости.

import os
import time
from asterisk.ami import AMIClient
client = AMIClient(address='127.0.0.1',port=5038)
client.login(username='admin',secret='7890ec8ff2955ec70a1b390b62f023da')
from asterisk.ami import EventListener

def event_listener(event,**kwargs):
    try:
       print(event)
    except:
       print("Something went wrong") 

client.add_event_listener(event_listener)

try:
    while True:
      time.sleep(1)
except (KeyboardInterrupt, SystemExit):
    client.logoff()

Все мои скрипты работают на астериске версии 13.29.2

boyapavel commented 2 years ago

скрипт многократно запускал и однажды он выдал одно сообщение, сразу после запуска. ощущение, что подтормаживает, принимает несколько событий из ami, а затем останавливается, либо окончательно виснет.

У меня стоит Asterisk certified/13.21-cert4

boyapavel commented 2 years ago

Поставил 13.29.2, вот все сообщения, которые выдает скрипт:

./ami_detector.py Event : FullyBooted -> {u'Privilege': u'system,all', u'Status': u'Fully Booted'}

boyapavel commented 2 years ago

глупый вопрос - а в вебе по результату должно что-то динамически обновляться, кроме появления записей в логе? например, канал разговаривающего закрашивается в другой цвет?

niaproxy commented 2 years ago

глупый вопрос - а в вебе по результату должно что-то динамически обновляться, кроме появления записей в логе? например, канал разговаривающего закрашивается в другой цвет?

На основной странице репозитория есть пример изображения - снизу справа от номера говорящего будет глиф и запись лог конференции.

Поставил 13.29.2, вот все сообщения, которые выдает скрипт:

./ami_detector.py Event : FullyBooted -> {u'Privilege': u'system,all', u'Status': u'Fully Booted'}

На новой версии попробуй запустить веб-интерфейс.

niaproxy commented 2 years ago

Только сейчас увидел письмо. Когда я только начинал делать эту фичу, я не знал про panoramisk, поэтому вдохновившись доками и парой статей в интернете начал делать на asterisk-ami.

Сейчас сам столкнулся с тем что тестовые скрипты зависают. Но тем не менее выдают события в первые несколько секунд.

boyapavel commented 2 years ago

написал парсер событий ConfbridgeTalking на panoramisk, сделал ему точку выхода - wget, как в коде views.py(event_listener_talk и event_listener_stoptalk) запустил его параллельно основному коду - появились события в логе, но глификоны не обновляются ( они откуда должны обновляться?

niaproxy commented 2 years ago

Весь код отвечающий за определенение говорящего и отображение глифа снизу

@asterisk.route('/get_talkers_on/<int:conf_number>/<callerid>')
def update_talkers_on(conf_number,callerid):
   message = gettext('Number %(num)s is talking.', num=callerid)
   conference = Conference.query.filter_by(number=conf_number).first_or_404()
   conference.log(message)
   sse_notify(conference.id, 'update_participants')
   return 'OK'

@asterisk.route('/get_talkers_off/<int:conf_number>/<callerid>')
def update_talkers_off(conf_number,callerid):
   message = gettext('Number %(num)s is fell silent.', num=callerid)
   conference = Conference.query.filter_by(number=conf_number).first_or_404()
   conference.log(message)
   sse_notify(conference.id, 'update_participants')
   return 'OK'

client = AMIClient(address='127.0.0.1',port=5038)
client.login(username=app.config['AMI_USER'],secret=app.config['AMI_PASSWORD'])
AutoReconnect(client)

def event_listener_talk(event,**kwargs):
    txt = event.keys['CallerIDNum']
    if str(txt).isdigit():
        talkers.append(txt)
        os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_on/%(conf)s/%(num)s 2>/dev/null', conf=event.keys['Conference'], num=txt))

client.add_event_listener(
    on_event=event_listener_talk,
    white_list='ConfbridgeTalking',
    TalkingStatus='on',
)

def event_listener_stoptalk(event,**kwargs):
    txt = event.keys['CallerIDNum']
    if str(txt).isdigit():
        talkers.remove(txt)
        os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_off/%(conf)s/%(num)s 2>/dev/null', conf=event.keys['Conference'], num=txt))

client.add_event_listener(
    on_event=event_listener_stoptalk,
    white_list='ConfbridgeTalking',
    TalkingStatus='off',
)

@asterisk.route('/online_participants.json/<int:conf_number>')
def online_participants_json(conf_number):
    ret = []
    ret2 = confbridge_list_participants(conf_number)
    conf = Conference.query.filter_by(number=conf_number).first()
    if not conf:
        return 'NOCONF'
    online_participants = [
        k['callerid'] for k in ret2]
    partici = [
        k.phone for k in conf.participants]

    for p in conf.participants:
                talking_gl = False
                if (p.phone in online_participants):
                        online = True
                        for i in ret2:
                                for num in talkers:
                                     if (  num == p.phone ):
                                          talking_gl = True
                                if (i['callerid'] == p.phone):
                                        flag = i['flags']
                                        channel = i['channel']
                else:
                        online = False
                        flag = ''
                        channel = ''
                ret.append({
                'id': p.id,
                'name': p.name,
                'phone': p.phone,
                'talking_gl': talking_gl,
                'callerid': p.phone,
                'is_invited': p.is_invited,
                'flags': flag,
                'channel': channel,
                'is_online': online
                }
                )

    for i in ret2:
            phone = i['callerid']
            talking_gl = False
            if (i['callerid'] not in partici):
                contac = Contact.query.filter_by(phone=i['callerid']).first()
                if ( contac ):
                    name = contac.name
                for num in talkers:
                    if (  num ==  i['callerid'] ):     
                        talking_gl = True

                else:
                    name=''                    
                ret.append ({
                'id': '',
                'name': name,
                'phone': phone,
                'talking_gl': talking_gl,
                'callerid': phone,
                'is_invited': False,
                'flags': i['flags'],
                'channel': i['channel'],
                'is_online': True
                 }
                 )
    return Response(response=json.dumps(ret),
                    status=200, mimetype='application/json')

Конткретно глиф определен в самом конце в переменной talking_gl Сначала ami наполняет словарь номера абонентов talkers - а затем функция online_participants_json парсит его для каждого участника на экране. Таблица стилей и html в папке templates если на что поменять внешне.

Можно переписать бэкенд на panaromiks. Главное сохранить переменную talkers - в ней должны быть номера тех кто в данный момент говорит и структуру внешних ссылок для обновления интерфейса(event_listener_talk).

boyapavel commented 2 years ago

Ура, добился глификонов) рассказываю:

  1. выносим парсер ami отдельно, запускаем параллельно(работает на третьем питоне через panoramisk):

`

import os
import asyncio
from panoramisk import Manager
from flask_babelex import lazy_gettext as _, gettext

exiting = False

ip = '127.0.0.1'
username =  'conf'
secret = '7890ec8ff2955ec70a1b390b62f023da'

client = Manager(loop=asyncio.get_event_loop(),
                host=ip,
                username=username,
                secret=secret)

@client.register_event('ConfbridgeTalking')
def Talking(manager, message):
    txt = message.CallerIDNum
    if (message.TalkingStatus == "on"):
        print("talking_on")
        os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_on/%(conf)s/%(num)s 2>/dev/null', conf=message.Conference, num=txt))
    elif (message.TalkingStatus == "off"):
        print("talking_off")
        os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_off/%(conf)s/%(num)s 2>/dev/null', conf=message.Conference, num=txt))

def main():
    client.connect()
    try:
        client.loop.run_forever()
    except KeyboardInterrupt:
        exiting = True
        client.loop.close()

if __name__ == '__main__':
    main()`
  1. комментируем часть кода в views.py(парсер через asterisk.ami более не нужен): `

    #client = AMIClient(address='127.0.0.1',port=5038) #client.login(username=app.config['AMI_USER'],secret=app.config['AMI_PASSWORD']) #AutoReconnect(client) # #def event_listener_talk(event,kwargs): # print(event.keys['CallerIDNum'],"talk") # txt = event.keys['CallerIDNum'] # if str(txt).isdigit(): # talkers.append(txt) # os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_on/%(conf)s/%(num)s 2>/dev/null', conf=event.keys['Conference'], num=txt)) # #client.add_event_listener( # on_event=event_listener_talk, # white_list='ConfbridgeTalking', # TalkingStatus='on', #) # #def event_listener_stoptalk(event,kwargs): # print(event.keys['CallerIDNum'],"stop_talk") # txt = event.keys['CallerIDNum'] # if str(txt).isdigit(): # talkers.remove(txt) # os.system(gettext('wget -O - --no-proxy http://localhost:5000/asterisk/get_talkers_off/%(conf)s/%(num)s 2>/dev/null', conf=event.keys['Conference'], num=txt)) # #client.add_event_listener( # on_event=event_listener_stoptalk, # white_list='ConfbridgeTalking', # TalkingStatus='off', #)`

  2. добавляем в функции update_talkers_on и update_talkers_off добавление и удаление в массив talkers:

` @asterisk.route('/get_talkers_on//') def update_talkers_on(conf_number,callerid): talkers.append(callerid) message = gettext('Number %(num)s is talking.', num=callerid) conference = Conference.query.filter_by(number=conf_number).first_or_404() conference.log(message) sse_notify(conference.id, 'update_participants') return 'OK'

@asterisk.route('/get_talkers_off/<int:conf_number>/<callerid>')
def update_talkers_off(conf_number,callerid):
talkers.remove(callerid)
message = gettext('Number %(num)s is fell silent.', num=callerid)
conference = Conference.query.filter_by(number=conf_number).first_or_404()
conference.log(message)
sse_notify(conference.id, 'update_participants')
return 'OK'
`
boyapavel commented 2 years ago

Премного благодарен, вам, Иван! Огромное, человеческое спасибо!