panoramisk icon indicating copy to clipboard operation
panoramisk copied to clipboard

Key Error

Open litnimax opened this issue 7 years ago • 6 comments

Hi! I got the following error (python3.6, panoramisk 1.1):

Exception in callback CallManager.set_result(<Future pendi...7149dfb88>()]>)(<Future finis...' content=''>>)
handle: <Handle CallManager.set_result(<Future pendi...7149dfb88>()]>)(<Future finis...' content=''>>)>
Traceback (most recent call last):
  File "/usr/lib/python3.6/asyncio/events.py", line 127, in _run
    self._callback(*self._args)
  File "/usr/lib/python3.6/site-packages/panoramisk/call_manager.py", line 37, in set_result
    call = self.calls_queues[uniqueid]
KeyError: ''

Please advise.

litnimax avatar Feb 07 '18 05:02 litnimax

I put some debug print and got:

1111 <Message ActionID='action/69408cea-e2c1-4590-b6e3-8b5775f28364/1/2' Message='Extension does not exist.' Response='Error' content=''>

Isn't it supposed to be catched and sent as exception?

litnimax avatar Feb 07 '18 05:02 litnimax

I put some correct extension, now calling:

call = yield from callmanager.send_originate({
        'Action': 'Originate',
        'Channel': 'Local/100@gsm-key-in',
        'WaitTime': 20,
        'CallerID': 'monitor',
        'Application': 'Echo',})

Result:

1111 <unknown> dict_items([('1517982752', <panoramisk.call_manager.Call object at 0x7efbff0cbfd0>)])
Exception in callback CallManager.set_result(<Future pendi...bff0c0af8>()]>)(<Future finis... content=''>]>)
handle: <Handle CallManager.set_result(<Future pendi...bff0c0af8>()]>)(<Future finis... content=''>]>)>
Traceback (most recent call last):
  File "/usr/lib/python3.6/asyncio/events.py", line 127, in _run
    self._callback(*self._args)
  File "/usr/lib/python3.6/site-packages/panoramisk/call_manager.py", line 39, in set_result
    call = self.calls_queues[uniqueid]
KeyError: '<unknown>'

Looking Asterisk debug:

.
Event: NewConnectedLine
Privilege: call,all
Channel: Local/100@gsm-key-in-00000007;2
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: <unknown>
CallerIDName: monitor
ConnectedLineNum: <unknown>
ConnectedLineName: monitor
Language: en
AccountCode:
Context: gsm-key-in
Exten: 100
Priority: 1
Uniqueid: 1517982752.15
Linkedid: 1517982752.14..
...
...
Event: OriginateResponse
Privilege: call,all
ActionID: action/a5d8550b-b6d4-4b54-a3d0-4f531a3a8b9c/1/2
Response: Failure
Channel: Local/100@gsm-key-in
Application: Echo
Data:
Reason: 0
Uniqueid: <unknown>
CallerIDNum: <unknown>
CallerIDName: monitor

Seems OriginateResponse did not get Uniqueid from leg A...

litnimax avatar Feb 07 '18 05:02 litnimax

This is due to async call origination.. In recent Asterisk they added ChannelId and OtherChannelId. Calling:

    call = yield from callmanager.send_originate({
        'Action': 'Originate',
        'Channel': 'Local/100@gsm-key-in',
        'WaitTime': 20,
        'CallerID': 'monitor',
        'ChannelID': uuid.uuid4().node,
        'OtherChannelID': uuid.uuid4().node,
        'Application': 'Echo',})

Now works!

litnimax avatar Feb 07 '18 06:02 litnimax

Have a look at this PR https://github.com/gawel/panoramisk/pull/60

gawel avatar Feb 07 '18 08:02 gawel

PR 60 looks working. But it will not help with unconnected calls. It's a well known Asterisk bug/feature about missing uniqueid of the failed call. That's why they added ChannelID and OtherChannelID params to Originate action. What if you add this to your code?

Also I found out that the below code hangs some time (from example/originate.pt:

while not call.queue.empty():
        event = call.queue.get_nowait()
        print(event)
    while True:
        event = yield from call.queue.get()
        print(event)
        if event.event.lower() == 'hangup' and event.cause in ('0', '17'):
            break
    callmanager.clean_originate(call)
    callmanager.close()

As the code is asynchrounous the events stream is not delivered as it is emittied from Asterisk. I mean that Hangup not always comes the last after all previsous messages like HangupRequest etc.. So it happens that Hangup event comes here:

while not call.queue.empty():
        event = call.queue.get_nowait()
        print(event)

and some other message comes here:

while True:
        event = yield from call.queue.get()
        print(event)
        if event.event.lower() == 'hangup' and event.cause in ('0', '17'):
            break

but there is no hangup message so there is no break and it hangs forever on yield from call.queue.get(). Here is my code that is always working:

    cause = None
    while not call.queue.empty():
        event = call.queue.get_nowait()
        if event.event.lower() == 'hangup':
            cause = event.cause
    if not cause:
        while True:
            event = await call.queue.get()
            if event.event.lower() == 'hangup':
                cause = event.cause
                break
    callmanager.clean_originate(call)
    return cause

litnimax avatar Feb 08 '18 21:02 litnimax

Feel free to provide a PR is you think you have a good patch :) CallManager is a POC (but it seems some people used it with success) so yeah, it may not be perfect.

gawel avatar Feb 13 '18 12:02 gawel