panoramisk
panoramisk copied to clipboard
Key Error
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.
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?
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...
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!
Have a look at this PR https://github.com/gawel/panoramisk/pull/60
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
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.