Giter VIP home page Giter VIP logo

panoramisk's Introduction

Panoramisk. The Asterisk's druid

image

image

image

image

image

image

Panoramisk is a library based on python's AsyncIO to play with Asterisk's manager.

It uses the TCP manager server to listen to events and send actions.

For basic usage, you have some examples in examples/ folder.

You can find some help on IRC: irc://irc.freenode.net/panoramisk (www)

Source code is available at https://github.com/gawel/panoramisk/

Check the full documentation

I've spent hours writing this software, with love. Please consider tiping if you like it:

BTC: 1PruQAwByDndFZ7vTeJhyWefAghaZx9RZg

ETH: 0xb6418036d8E06c60C4D91c17d72Df6e1e5b15CE6

LTC: LY6CdZcDbxnBX9GFBJ45TqVj8NykBBqsmT

panoramisk's People

Contributors

anxolerd avatar areski avatar burik666 avatar dependabot[bot] avatar drwowa avatar edrmp avatar gawel avatar grendel7 avatar jordanrinke avatar litnimax avatar ludovic-gasc avatar ovv avatar phaseowner avatar romkazor avatar sisoftrg avatar theclanks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

panoramisk's Issues

Error after callee answer

Python 3.7
call = await _AMI_MANAGER.send_action({...})

DEBUG:panoramisk.manager:message interpreted: <Message ActionID='action/0db9ad0a-4f02-4cb2-b8e3-65b78ff88291/1/7' Message='Originate successfully queued' Response='Success' content=''>
ERROR:asyncio:Fatal error: protocol.data_received() call failed.
protocol: <panoramisk.ami_protocol.AMIProtocol object at 0x7f26e91954a8>
transport: <_SelectorSocketTransport fd=6 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/asyncio/selector_events.py", line 824, in _read_ready__data_received
    self._protocol.data_received(data)
  File "/usr/local/lib/python3.7/site-packages/panoramisk/ami_protocol.py", line 72, in data_received
    self.handle_message(message)
  File "/usr/local/lib/python3.7/site-packages/panoramisk/ami_protocol.py", line 79, in handle_message
    if response.add_message(message):
  File "/usr/local/lib/python3.7/site-packages/panoramisk/actions.py", line 88, in add_message
    multi = self.multi
  File "/usr/local/lib/python3.7/site-packages/panoramisk/actions.py", line 69, in multi
    elif msg.endswith('successfully queued') and self['async'] != 'false':
  File "/usr/local/lib/python3.7/site-packages/panoramisk/utils.py", line 179, in __getitem__
    return self._store[key.lower()][1]
KeyError: 'async'
ERROR:panoramisk.manager:Connection lost
INFO:panoramisk.manager:Try to connect again in 2 seconds

Adding an agent into a queue

Hello,

I had a probelm with adding an agent into a queue, with send_action() not returning back a message. Dug deeper and found that this line is causing the issue:

elif msg.startswith('added') and msg.endswith('to queue'):

This causes multi to be true, but len(self.responses) is still one, and add_message will return false. I have temporarly disabled that check and everything is running fine.

Listening for Events and Action results simultaneously

Hello,

I am writing a program where I need to listen to events and get the results of actions continuously. Ideally I want to put the events and action results into an asyncio queue and process that queue. Been trying to get this working for past two days, but its not yet successful. Here is my current code:

I have an ActionListener which continuously send_action() and put() the result into a queue. Similarly I have an EventsListener which pushes all received events to a queue, and finally an EventsProcess which fetches items from the queue and processes it.

All these three are run in a main program using multiprocessing.Process()

action_listener.py:

import asyncio
import logging

from panoramisk import Manager

class ActionListener:
    def __init__(self, options, queue):
        self.loop = asyncio.get_event_loop()
        self.events_queue = queue

        self.manager = Manager(loop=self.loop, **options)
        self.manager.log.addHandler(logging.NullHandler())

    async def ping(self):
        await self.manager.connect()
        while True:
            message = await self.manager.send_action({'Action': 'ping'})
            print (f"action: putting a message into queue")
            # p = yield from self.manager.send_action({'Action': 'SIPpeers'})                                                                                                       
            await self.events_queue.put(message)
            await asyncio.sleep(5)
        self.manager.close()


    def run(self):
        self.loop.run_until_complete(self.ping())
        self.loop.close()

events_listener.py:

import asyncio
import logging

from panoramisk import Manager

class EventsListener:
    def __init__(self, options, queue):
        self.loop = asyncio.get_event_loop()
        self.events_queue = queue

        self.manager = Manager(loop=self.loop, **options)
        self.manager.log.addHandler(logging.NullHandler())
        self.manager.register_event("*", self.handle_events)

    async def handle_events(self, manager, message):
        print (f"events: putting a message into queue")
        await self.events_queue.put(message)

    async def connect(self):
        await self.manager.connect()

    def run(self):
        try:
            self.loop.run_until_complete(self.connect())
            self.loop.run_forever()
        finally:
            self.loop.close()

events_process.py:

import asyncio
import logging
from pprint import pprint

class EventsProcess:
    def __init__(self):
        self.loop = asyncio.get_event_loop()
        self.events_queue = asyncio.Queue()

    async def process(self):
        while True:
            message = await self.events_queue.get()
            pprint (message)

    def get_queue(self):
        return self.events_queue

    def run(self):
        self.loop.run_until_complete(self.process())
        self.loop.close()

and finally the main program is as follows:

from multiprocessing import Process

from events_listener import EventsListener
from action_listener import ActionListener
from events_process import EventsProcess
def run_events_listener(config, events_queue):
    listener = EventsListener(config["manager"], events_queue)
    listener.run()

def run_action_listener(config, events_queue):
    action = ActionListener(config["manager"], events_queue)
    action.run()

def run_events_process(p):
    p.run()

def main(args=None):
    p = EventsProcess()
    events_queue = p.get_queue()

    p1 = Process(name="erbot_events", target=run_events_listener, args=(config, events_queue,))
    p2 = Process(name="erbot_actions",target=run_action_listener, args=(config,events_queue,))
    p3 = Process(name="erbot_process",target=run_events_process, args=(p,))

    p1.start()
    p2.start()
    p3.start()

In the above program, message = await self.events_queue.get() do not seems to be working. No message is being printed, though I can see that putting events does work.

I have removed all unnecessary parts from the program and just posted the bare bones of it. I am sure I am missing some thing with running both action and events together.

I am sure many too would have similar requirement and a working example of both action and events in tandem would be of much help for some one new to this project.

doubt

in this case, how i use 'queues_details' for my script?

import asyncio
from panoramisk import Manager
from pprint import pprint

@asyncio.coroutine
def queue_status():
manager = Manager(loop=asyncio.get_event_loop(),
host='127.0.0.1', port=5039,
username='username', secret='mysecret')
yield from manager.connect()
queues_details = yield from manager.send_action(
{'Action': 'QueueStatus', 'Queue': 'queue_name'})
manager.close()
pprint(queues_details)

def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(queue_status())
loop.close()

if name == 'main':
main()

No response from action `QueueAdd`

When sending the action QueueAdd I get no response and it just hangs.

I was able to fix this with overriding Action and removing the lines 64 & 65:

        elif msg.startswith('added') and msg.endswith('to queue'):
            return True

from def multi().

I'm not sure, if this breaks other functionality though.

Asterisk 13.16.0

failed in originate

Hi, I tested your originate.py sample. If the call is answered, everything is fine, but if no answer or busy, then I get

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

Maybe the problem is related to `call_manager.py`

Question about event_listener and send_action in class

Hello. I wondered if you'd help me. I want to change def callback to class CallBack

Without class:

@manager.register_event('*')
def callback(manager, message):
    if "Newchannel" in message.event:
    print(message)
    status =  yield from manager.send_action({'Action': 'Status'})
    print(status)

In this scheme all ok

With class:

@manager.register_event('*')
class CallBack(object)
    def __init__(self, manager, message):
        self.manager = manager
        self.message = message
        self.start()

    def send_action(self):
        yield from manager.send_action({'Action': 'Status'})

    def start(self):
        if "Newchannel" in message.event:
        status = self.send_action()
        print(status)

But if i change def callback to class, i get <generator object CallBack.send_action at 0x7fd21e1710a0>
If I try to change generator to list i get yield from wasn't used with future

Add job timer

Hello. How about add job timer? Because sometimes you need to do some job(action) with some frequency (5,30,60 sec etc) in active ami session. Thanks.

fast_agi send_command can't handle multiple responses from GOSUB

I'm currently playing around with the FastAGI part of this library. I can call many different AGI commands without any problem through the library, but I have some issues with the GOSUB command.

Most commands only send one response when they are done. However, GOSUB normally sends two responses, a 100 result=0 Trying... when the command is started and a 200 result=0 Gosub complete when the command is done. https://github.com/asterisk/asterisk/blob/13.24/apps/app_stack.c#L1224

However, Panoramisk currently doesn't accept either of that behaviour. When running the GOSUB command, it does not recognize the 100 status code, and will parse this as an AGIUnknownError.

def agi_code_check(code=None, response=None, line=None):

IMO, the way to fix this is to edit send_command, check for 100 status codes (or possibly all codes < 200) and if such a response is returned, wait again for the next response and return that instead.

not exit fit not answered

Hi, i tried a bit but i cannot figure how to fix this behaviour:

<panoramisk.call_manager.Call object at 0x7635dbf0>

it appear when the originate call is not answered. No problem if the call is answered and hang-up or hang-up directly. It crash just when let's ringing and close itself.

Any advice? Thanks

Method send_action

from panoramisk import Manager, Action, Message
import asyncio

loop = asyncio.get_event_loop()

manager = Manager(
    host='192.168.0.1',
    username='user',
    secret='user',
    port=5038,
    ssl=False,
    encoding='utf8',
    loop=loop
)

manager.connect()

@asyncio.coroutine
def run():
    manager = Manager()
    result = loop.call_later(1, manager.send_action({'Action': 'Status'}))
    return result

def main():
    result = loop.run_until_complete(run())
    return result

result = main()
print(result)
TimerHandle(90460.749009724, <Response CaseInsensitiveDict({'Response': 'Failed'})>, ())

Here https://github.com/gawel/panoramisk/blob/master/panoramisk/__init__.py#L381
kwargs does not contains 'callback' and starts self.send_action_via_http method,
but ajam and http-asterisk is not installed.

Q1: How and what callback i can put in send_action of my function run?
Q2: Or may you have a complete example of async call?
Thank you very match

Incomplete AMI Action Response

Hi!

I used your library to make small control systems on PBXs. When the server with Panoramisk and the Asterisk server are close (low latency) there are no problems.

On the other hand, if the two servers are far away (like Finland my server, and Brazil Asterisk server), communication presents difficulties when trying to send an AMI action, in my case "QueueStatus".

Code example (sending a "QueueStatus" AMI Action):

        # Every AMI Action uses its own event loop
        action_event_loop = asyncio.new_event_loop()

        # Init the Asterisk Manager Interface
        manager: Manager = Manager(loop=action_event_loop, host=host, 
                                   port=port, username=username, secret=secret)

        # Login to the AMI
        try:
            action_event_loop.run_until_complete(manager.connect())
        except OSError:
                raise AMIConnectionError('Can\'t connect to following AMI '
                                         'server: %s' % host)
        # Send the AMI Action
        ami_action_result = action_event_loop.run_until_complete(
            manager.send_action({'Action': 'QueueStatus'}))

        # Create a list with all response sections
        ami_response: List[Message] = []
        if isinstance(ami_action_result, list):
            ami_response = ami_action_result
        else:
            ami_response = [ami_action_result, ]

        # If the command sent has not a successful response log a warning.
        if not ami_response[0].success:
            logger.warning('The following action sent to %s is not '
                            'successful: %s' % (host, self.action_params))

        # Save the AMI Action response and close the AMI connection
        self.response = ami_response
        manager.close()

        # Close the asyncio loop and return the AMI Action response
        action_event_loop.close()
        return self.response

In this example the problem is that the AMI Response is incomplete: only a Message (QueueParams) is returned from .send_action() method. Normally this returns a complete list of Message objects with all PBX queues informations.

I checked the source code of Panoramisk but it is not clear to me exactly how the answers are read and parserized with the asyincio socket connection (the end of the AMI Action Response is checked before returning the Message object? If not, can a check that waits for the response end be added?).

I noticed that if I run a time.sleep(0.2) after manager.connect() and then send the AMI action this problem does not occur 70% of the time. I can't understand why.

I thank you in advance for your support and for creating this great library!

Handling AGI errors

Hello,

I can see that FastAGI returns errors in response, instead of raising exceptions, which is very un-Pyhonic. What is the rationale behind that, and what is the recommended way of handling AGI errors in one place?

error using for playDTMF

Hi, I'm using this library for a while, thanks for your effort.
recently I tried using that for playing dtmf with action playDTMF
it plays beep sound but gives error as output, and code hangs, with this error:

Exception in callback _SelectorSocketTransport._read_ready()
handle: <Handle _SelectorSocketTransport._read_ready()>
Traceback (most recent call last):
File "/usr/lib64/python3.6/asyncio/events.py", line 145, in _run
self._callback(*self._args)
File "/usr/lib64/python3.6/asyncio/selector_events.py", line 721, in _read_ready
self._protocol.data_received(data)
File "/opt/qs_main/qs_mainenv/lib64/python3.6/site-packages/panoramisk/ami_protocol.py", line 72, in data_received
self.handle_message(message)
File "/opt/qs_main/qs_mainenv/lib64/python3.6/site-packages/panoramisk/ami_protocol.py", line 79, in handle_message
if response.add_message(message):
File "/opt/qs_main/qs_mainenv/lib64/python3.6/site-packages/panoramisk/actions.py", line 92, in add_message
multi = self.multi
File "/opt/qs_main/qs_mainenv/lib64/python3.6/site-packages/panoramisk/actions.py", line 71, in multi
elif msg.endswith('successfully queued') and self['async'] != 'false':
File "/opt/qs_main/qs_mainenv/lib64/python3.6/site-packages/panoramisk/utils.py", line 179, in getitem
return self._store[key.lower()][1]
KeyError: 'async'

would you please guide me through solving this issue?
thanks

Asterisk 16 no newexten

Hello,

In Asterisk 16.2.1~dfsg-1+deb10u1 on debian 10
I cannot detect "Newexten" event, even with '*' i can't have all event.

@manager.register_event('Newexten')
def callback(manager, message):
    if message.Application == "NoOp" and not message.AppData == "":
        print(message.Channel + " : " + message.AppData)
        resultTmp = str(message.AppData).split(" : ")
        thisdict[resultTmp[0]] = resultTmp[1]

But on Asterisk 13.14.1~dfsg-2+deb9u4 on debian 9
The same code work

Have you any idea why ?

Error: CallManager.set_result()

I try to run originate.py script (python 3.4, panoramisk 1.1.dev) on asterisk 11.21 and get error:

Exception in callback CallManager.set_result(<Future pendi...sk._wakeup()]>)(<Future finis...' content=''>>)
handle: <Handle CallManager.set_result(<Future pendi...sk._wakeup()]>)(<Future finis...' content=''>>)>
Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/events.py", line 120, in _run
    self._callback(*self._args)
  File "/usr/local/lib/python3.4/dist-packages/panoramisk-1.1.dev0-py3.4.egg/panoramisk/call_manager.py", line 32, in set_result
    event = result.result()[-1]
  File "/usr/local/lib/python3.4/dist-packages/panoramisk-1.1.dev0-py3.4.egg/panoramisk/utils.py", line 191, in __getitem__
    return self._store[key.lower()][1]
AttributeError: 'int' object has no attribute 'lower'

ChanVariable

Hello. Is there an easy way to get ChanVariable in panomarisk lib?
In other lib i can use event['ChanVariable']['SomeKey'] but in panomarisk ChanVariables is a list

trying something simple from the example...

Any idea why I can't get the example to execute? Maybe 3.6 isn't supported?

import asyncio
import panoramisk

manager = panoramisk.Manager(loop=asyncio.get_event_loop(),
                  host='ip',
                  username='user',
                  secret='secret')
$ python3.6 panoramisk.py
Traceback (most recent call last):
  File "panoramisk.py", line 5, in <module>
    import panoramisk
  File "/home/bbaumg/panoramisk.py", line 8, in <module>
    manager = panoramisk.Manager(loop=asyncio.get_event_loop(),
AttributeError: module 'panoramisk' has no attribute 'Manager'

hi, can you help me with panoramisk?

from panoramisk import Manager, Action, Message
import asyncio

loop = asyncio.get_event_loop()

manager = Manager(
    host='192.168.0.1',
    username='user',
    secret='user',
    port=5038,
    ssl=False,
    encoding='utf8',
    loop=loop
)

def handle_meetme(event, manager):
    """ do stuff with the event
    """
    print(event, manager)
    import ipdb; ipdb.set_trace()

manager.register_event('Meetme*', handle_meetme)

manager.connect()

loop.call_later(5, manager.send_action({
    'Action': 'Originate',
    'Channel': 'Local/number@calldebts-dispatch',
    'WaitTime': 1,
    'CallerID': 'user',
    'Exten': 'debts',
    'Context': 'rings',
    'Priority': 1,
}))

loop.run_forever()

TraceBack:
Exception in callback <Response CaseInsensitiveDict({'Response': 'Failed'})>()
handle: TimerHandle(77281.199818058, <Response CaseInsensitiveDict({'Response': 'Failed'})>, ())
Traceback (most recent call last):
File "/home/sva/ENV/lib/python3.3/site-packages/asyncio-0.4.1-py3.3.egg/asyncio/events.py", line 39, in _run
self._callback(*self._args)
TypeError: 'Message' object is not callable

Multiple connection when using manager.send_action()

Hello, I'm new in python and I want to optimalize my script. Please, is there a way how to use manager.send_action() multiple times in one script without creating multiple connections ?

Depending on queue_status example I create class and I want to in init() set up manager and in others methods don't create new manager connection.
e.g.

class AmiClient:
'''
Initialize manager
'''
def __init__(self):
    # Set up connection manager
    self.manager = Manager(loop=asyncio.get_event_loop(),
              host=self.amiHost,
              username=self.amiUser,
              secret=self.amiPass)
    self.foo()

'''
Get variable from channel
'''
def foo(self):
    loop = asyncio.get_event_loop()
    channels = loop.run_until_complete(self.getChannels())
    variable = loop.run_until_complete(self.getVar(var,channel))
    # another call
    variable2 = loop.run_until_complete(self.getVar(var2,channel))

'''
Get all active core channels
'''
@asyncio.coroutine
def getChannels(self):
    yield from self.manager.connect()
    channels = yield from self.manager.send_action({'Action': 'CoreShowChannels'})
    return channels

'''
Get variable from channel
'''
@asyncio.coroutine
def getVar(self, var, channel):
    yield from self.manager.connect()
    variable = yield from self.manager.send_action({
        'Action': 'Getvar',
        'Channel': channel,
        'Variable' : var
        })
    if variable.Value:
        return variable.Value
    else:
        return None

Thank you.

PyPi update

Since 2018 no one update panoramisk on pypi
1.3.1 maybe?
Thanks!

Some help

Hi guys,

Thanks for this great library. I need to listen to some events in Asterisk Manager Interface and send related info to a client connected via browser, then I'd like to use this library with Django and Websocket, any hint about this respect?.

Thanks in advance.

AttributeError: 'NoneType' object has no attribute 'send' in manager.py line 138 - panoramisk 1.3

Hi,

Please bear in mind that I am quite new to Python, so I may make little to no sense below (read I have much to learn).

When trying to send a command from the Panoramisk Manager, I get the error as per above, referencing to Manager.prototype.send. The applicable part of my code is as below.

manager = panoramisk.Manager(
#host, port, username, secret
)

def handle_response(response):
    print(response)

response = manager.send_command('queue show 510')
response.add_done_callback(handle_response)

I have tried with and without a manager.connect() directly after declaring my manager object, with no difference found.

Upon getting the aforementioned error, I have looked into the originating file, manager.py, and finding that the indentation of the initial try block in the connection_made function making no sense to me (lines 57 - 56). I believe that they may need to be indented another level, however upon doing this, I find no difference to my own problem.

I do find that when i pprint(self.protocol), it does indeed return None.

I'm not quite sure what more I can do with my limited knowledge, can you provide any suggestions which might help me to resolve this?

Thanks.

Support multi-values for Action headers

Some AMI commands like Originate have a header you can use several times. For example, in Originate, you can have Variable header several times to set several variables in the context.

My idea to support that in Panoramisk, is to permit to pass an set or list of values in headers, example:

    {'Action': 'Originate',
    'Channel': 'Local/gpasgrimaud@bearstech',
    'WaitTime': 20,
    'CallerID': 'gawel',
    'Exten': '4260',
    'Context': 'bearstech',
    'Priority': 1,
    'Variable': ['__call_id=1', '__subroutine=playback'] }

If somebody wants to implement that instead of me or has a suggestion, be my guest.

New release

Would it be possible to release version 1.3 ?
Having a release with python 3.7 compatibility on PyPI would make things easier for us.

event does not work

Simple example
function callback never works

from panoramisk import Manager
import asyncio

manager = Manager(
    loop=asyncio.get_event_loop(),
    host='127.0.0.1',
    port=5038,
    # ssl=False,
    # encoding='utf8',
    username='amiuser',
    secret='amiuser1'
)


@manager.register_event('*')
def callback(manager, message):
    print('************', message)


def main():
    manager.connect()
    try:
        manager.loop.run_forever()
    except KeyboardInterrupt:
        manager.loop.close()


if __name__ == '__main__':
    main()

output

ssh://[email protected]:22/bin/python3.6 -u /home/asterisk/aster_helper/panoramisk_test.py
<Message AccountID='amiuser' Event='SuccessfulAuth' EventTV='2019-02-26T09:27:25.390+0300' EventVersion='1' File='manager.c' Func='manager_default_msg_cb' Line='1848' LocalAddress='IPV4/TCP/127.0.0.1/5038' Privilege='security,all' RemoteAddress='IPV4/TCP/127.0.0.1/38918' SequenceNumber='1125' Service='AMI' SessionID='0x7f9d0c000ff0' SessionTV='2019-02-26T09:27:25.390+0300' Severity='Informational' UsingPassword='0' content=''>
<Message AccountID='101' Challenge='64a33c66' Event='ChallengeSent' EventTV='2019-02-26T09:28:02.124+0300' EventVersion='1' File='manager.c' Func='manager_default_msg_cb' Line='1848' LocalAddress='IPV4/UDP/192.168.1.145/5060' Privilege='security,all' RemoteAddress='IPV4/UDP/192.168.1.108/56460' SequenceNumber='1126' Service='SIP' SessionID='0x7f9d300009c0' Severity='Informational' content=''>
<Message AccountID='102' Challenge='702a60ef' Event='ChallengeSent' EventTV='2019-02-26T09:28:02.124+0300' EventVersion='1' File='manager.c' Func='manager_default_msg_cb' Line='1848' LocalAddress='IPV4/UDP/192.168.1.145/5060' Privilege='security,all' RemoteAddress='IPV4/UDP/192.168.1.108/56460' SequenceNumber='1127' Service='SIP' SessionID='0x7f9d3000c5a0' Severity='Informational' content=''>
<Message AccountID='101' Event='SuccessfulAuth' EventTV='2019-02-26T09:28:02.147+0300' EventVersion='1' File='manager.c' Func='manager_default_msg_cb' Line='1848' LocalAddress='IPV4/UDP/192.168.1.145/5060' Privilege='security,all' RemoteAddress='IPV4/UDP/192.168.1.108/56460' SequenceNumber='1128' Service='SIP' SessionID='0x7f9d300009c0' Severity='Informational' UsingPassword='1' content=''>
<Message AccountID='102' Event='SuccessfulAuth' EventTV='2019-02-26T09:28:02.148+0300' EventVersion='1' File='manager.c' Func='manager_default_msg_cb' Line='1848' LocalAddress='IPV4/UDP/192.168.1.145/5060' Privilege='security,all' RemoteAddress='IPV4/UDP/192.168.1.108/56460' SequenceNumber='1129' Service='SIP' SessionID='0x7f9d3000c5a0' Severity='Informational' UsingPassword='1' content=''>
<Message Address='192.168.1.108:56460' ChannelType='SIP' Event='PeerStatus' File='manager.c' Func='manager_default_msg_cb' Line='1848' Peer='SIP/101' PeerStatus='Registered' Privilege='system,all' SequenceNumber='1130' content=''>
<Message Address='192.168.1.108:56460' ChannelType='SIP' Event='PeerStatus' File='manager.c' Func='manager_default_msg_cb' Line='1848' Peer='SIP/102' PeerStatus='Registered' Privilege='system,all' SequenceNumber='1131' content=''>

response from register_event

Hi again. And one more question.
Where i can find handlers after manager.register_event an manager.send_action with 'Action': 'Originate', 'Async': 'yes'?

import asyncio

from panoramisk import Manager, Action, Message

from tasks.model import Tasks


loop = asyncio.get_event_loop()
manager = Manager(
    host='192.168.0.1',
    url='http://192.168.0.1:8088/asterisk/arawman',
    username='bla,
    secret='bla',
    port=5038,
    ssl=False,
    encoding='utf8',
    loop=loop
)

def handle_hangup(event, manager):
    """ do stuff with the event
    """
    import ipdb; ipdb.set_trace()
    print(event, manager)

manager.register_event('Hangup', handle_hangup)

@asyncio.coroutine
def make_calls(future, number, provider_id):
    result = manager.send_action({
        'Action': 'Originate',
        'Channel': 'Local/%s@calldebts-dispatch' % number,
        'WaitTime': 20,
        'CallerID': 'user',
        'Exten': 'debts',
        'Context': 'rings',
        'Priority': 1,
        'Async': 'yes',
        'Variable': 'provider_id=%s' % provider_id
    })
    future.set_result(result)

if __name__ == '__main__':
    provider_id = 'id1'
    future = asyncio.Future()
    numbers = ['2', '1']
    for number in numbers:
        asyncio.Task(make_calls(future, number, provider_id))

    loop.run_until_complete(future)
    loop.close()

Use of "@coroutine" decorator. (deprecated since Python 3.8)

Some deprecation warnings poped up. I am using Python 3.8.5.

  .../panoramisk/panoramisk/manager.py:102: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
    def send_awaiting_actions(self, *_):

  .../panoramisk/panoramisk/fast_agi.py:18: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
    def send_command(self, command):

  ...src/panoramisk/panoramisk/fast_agi.py:53: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
    def _read_result(self):

  .../panoramisk/panoramisk/fast_agi.py:133: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
    def handler(self, reader, writer):

This programming pattern shows up in the example folder as well. For the manager example and my usecase it just works™ to substitute the the decorators to async def and yield from to await.

Allow recurring ping + interval in config ?

The code uses a ping method for the Manager Object, but does not check that the connection is really alive from the Manager point of view.

Maybe there is a risk that the connection dies silently, without a recurring ping from the Panoramisk App.

My 2c€ :

  • Either warn the lib user to check regularly that the connection is alive : the case in which this happens is especially when listening to events and not sending new Actions.
  • or integrate a ping in the Manager code and config, with a specified interval, and forcing reconnects from the manager when the ping is KO.

panoramisk not capturing result of Async AGI command

Hello,

I've been experimenting with panoramisk lately, and I've discovered what I believe to be a bug, and also a potential solution for it. However, I'm opening an issue rather than a pull request since I'm by no means an expert in either panoramisk or asyncio.

The following statements:

action = actions.Command({'Action': 'AGI',
                          'Channel': agi['agi_channel'],
                          'Command': 'GET FULL VARIABLE ${PJSIP_HEADER(read,Call-ID)}'},
                          as_list=True)
res = await manager.send_action(action)

do not yield a result with code from the current git master. After digging a little, I found that in def completed(self) in actions.py, none of the conditions match the AsyncAGIExec event asterisk produces, and which carries the result. A patch as simple as:

--- a/panoramisk/actions.py
+++ b/panoramisk/actions.py
@@ -90,6 +90,8 @@
         resp = self.responses[-1]
         if resp.event.endswith('Complete'):
             return True
+        elif resp.event in ('AsyncAGIExec'):
+            return True
         elif resp.subevent in ('End', 'Exec'):
             return True
         elif resp.response in ('Success', 'Error', 'Fail', 'Failure'):

seems to fix that, but I'm not sure if that's the best approach here.

Here's the sequence of actions/events the send_action above triggers:

<--- Examining AMI action: -->
Action: AGI
ActionID: action/186daec3-bfdc-437d-b110-1fb7cfc019d8/1/1196
Channel: PJSIP/test-gd-0000003d
Command: GET FULL VARIABLE ${PJSIP_HEADER(read,Call-ID)}
CommandID: command/1ac20057-d646-431e-87aa-976b15caa68a/1/3

<-- Examining AMI event: -->
Event: AGIExecStart
Privilege: agi,all
SequenceNumber: 964
File: manager.c
Line: 1864
Func: manager_default_msg_cb
SystemName: mgw0-stage-tis0-cn1
Channel: PJSIP/test-gd-0000003d
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: test-gd
CallerIDName: stage
ConnectedLineNum: <unknown>
ConnectedLineName: <unknown>
Language: gr
AccountCode: 165
Context: endpoints-in
Exten: 123456
Priority: 1
Uniqueid: mgw0-stage-tis0-cn1-1653995979.61
Linkedid: mgw0-stage-tis0-cn1-1653995979.61
CommandId: 1082775508
Command: GET FULL VARIABLE ${PJSIP_HEADER(read,Call-ID)}


<-- Examining AMI event: -->
Event: AGIExecEnd
Privilege: agi,all
SequenceNumber: 965
File: manager.c
Line: 1864
Func: manager_default_msg_cb
SystemName: mgw0-stage-tis0-cn1
Channel: PJSIP/test-gd-0000003d
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: test-gd
CallerIDName: stage
ConnectedLineNum: <unknown>
ConnectedLineName: <unknown>
Language: gr
AccountCode: 165
Context: endpoints-in
Exten: 123456
Priority: 1
Uniqueid: mgw0-stage-tis0-cn1-1653995979.61
Linkedid: mgw0-stage-tis0-cn1-1653995979.61
CommandId: 1082775508
Command: GET FULL VARIABLE ${PJSIP_HEADER(read,Call-ID)}
ResultCode: 200
Result: Success


<-- Examining AMI event: -->
Event: AsyncAGIExec
Privilege: agi,all
SequenceNumber: 966
File: manager.c
Line: 1864
Func: manager_default_msg_cb
SystemName: mgw0-stage-tis0-cn1
Channel: PJSIP/test-gd-0000003d
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: test-gd
CallerIDName: stage
ConnectedLineNum: <unknown>
ConnectedLineName: <unknown>
Language: gr
AccountCode: 165
Context: endpoints-in
Exten: 123456
Priority: 1
Uniqueid: mgw0-stage-tis0-cn1-1653995979.61
Linkedid: mgw0-stage-tis0-cn1-1653995979.61
Result: 200%20result%3D1%20(586f113295b1f8b6dd9dc39bcedfdc80)%0A
CommandId: command/1ac20057-d646-431e-87aa-976b15caa68a/1/3

After the patch, the future contains two items in a list, the first holding the Message='Added AGI command to queue' and Response='Success' keys (this event doesn't show up in asterisk manager debug, wonder why), the second the contents of AsyncAGIExec event above, including the Result key which carries the information needed.

script freezing than send originate failed

I face the following problem when creating originate:

When creating originate with "async: false" using manager.send_action and call fails, I receive message
<Message ActionID='action/02eec16a-b92f-4682-a551-918df9c27b07/1/163' Message='Originate failed' Response='Error' content=''>

When creating originate using manager.send_action with "async: true" or using callmanager.send_originate and call fails, then program freezes on line
call = yield from callmanager.send_originate({...})

In separate window I'm catching events OriginateResponse and see
<Message ActionID='action/3fdcc20c-7299-479d-bf98-631a5bb7904c/1/2' CallerIDName='testcall' CallerIDNum='<unknown>' Channel='SIP/test1-01/48727xxxxxx' Context='' Event='OriginateResponse' Exten='' Privilege='call,all' Reason='5' Response='Failure' Uniqueid='<null>' content=''>

An example of event when call is successful:
<Message ActionID='action/8d6fa9cb-a263-4bed-b381-28b305f4df03/1/2' CallerIDName='testcall' CallerIDNum='<unknown>' Channel='Local/48727xxxxxx@amicall-00000031;1' Context='amicall' Event='OriginateResponse' Exten='48727xxxxxx' Privilege='call,all' Reason='4' Response='Success' Uniqueid='1459861026.799672' content=''>

1.1 Release

For us, after #51 discussion will be finished, Panoramisk is ready to be tagged for 1.1.

Ideally, before the Debian freeze, it should be cool ;-)

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.

Documentation fix : need Login + secret in config + example

The manager actually connects (Logins) with a user from **config
panoramisk.Manager(**config)[source]

My suggestions :

I suggest updating the basic example from doc by dumping the content of config that contains Login and Secret.

how to parse output of actions to json

Hi
is there a way to parse output of panoramisk, to json?
for example the output of set actions commands for extension status is like below:

is there a way to get output in json, or a way to parse this to get only as below:
{StatusText : 'Unavailable'}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.