Skip to content

Commit

Permalink
Rework dialplan
Browse files Browse the repository at this point in the history
Current dialplan was not correct and complicated. This rework
simplify it greatly and provide an easy way to do your own routing

I think it will be a nice place to put helpers for
authentifications.

No idea if that will provide any advantages over a flat mapping
of methods / middlewares

issue #78
  • Loading branch information
ovv committed Apr 19, 2018
1 parent 01a015e commit 659f010
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 79 deletions.
33 changes: 17 additions & 16 deletions aiosip/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from . import __version__
from .dialog import Dialog
from .dialplan import Dialplan
from .dialplan import BaseDialplan
from .protocol import UDP, TCP, WS
from .peers import UDPConnector, TCPConnector, WSConnector
from .message import Response
Expand All @@ -39,7 +39,7 @@ def __init__(self, *,
middleware=(),
defaults=None,
debug=False,
dialplan=None,
dialplan=BaseDialplan(),
dns_resolver=aiodns.DNSResolver()
):

Expand All @@ -62,7 +62,7 @@ def __init__(self, *,
self._middleware = middleware
self._tasks = list()

self.dialplan = dialplan or Dialplan()
self.dialplan = dialplan
self.dialog_factory = dialog_factory
self.loop = loop

Expand Down Expand Up @@ -162,30 +162,31 @@ async def _run_dialplan(self, protocol, msg):
via_addr = via['host'], int(via['port'])
peer = await connector.get_peer(protocol, via_addr)

router = await self.dialplan.resolve(
username=msg.from_details['uri']['user'],
protocol=peer.protocol,
local_addr=peer.local_addr,
remote_addr=peer.peer_addr
)

async def reply(*args, **kwargs):
dialog = peer._create_dialog(
method=msg.method,
from_details=Contact.from_header(msg.headers['To']),
to_details=Contact.from_header(msg.headers['From']),
call_id=call_id
call_id=call_id,
inbound=True
)

await dialog.reply(*args, **kwargs)
await dialog.close(fast=True)

if not router:
await reply(msg, status_code=501)
return
try:
route = await self.dialplan.resolve(
username=msg.from_details['uri']['user'],
message=msg,
protocol=peer.protocol,
local_addr=peer.local_addr,
remote_addr=peer.peer_addr
)
except Exception as e:
LOG.exception(e)
route = None

route = router.get(msg.method)
if not route:
if not route or not asyncio.iscoroutinefunction(route):
await reply(msg, status_code=501)
return

Expand Down
44 changes: 2 additions & 42 deletions aiosip/dialplan.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,7 @@
LOG = logging.getLogger(__name__)


class Dialplan:
def __init__(self, default=None):
self._users = {}
self.default = default

async def resolve(self, username, protocol, local_addr, remote_addr):
class BaseDialplan:
async def resolve(self, message, username, protocol, local_addr, remote_addr):
LOG.debug('Resolving dialplan for %s connecting on %s from %s via %s',
username, local_addr, remote_addr, protocol)
router = self._users.get(username)
if not router:
router = self._users.get('*', self.default)
return router

def add_user(self, username, router):
self._users[username] = router


class Router(MutableMapping):
def __init__(self, default=None):
self._routes = {}
if default:
self._routes['*'] = default

# MutableMapping API
def __eq__(self, other):
return self is other

def __getitem__(self, key):
try:
return self._routes[key.lower()]
except KeyError:
return self._routes['*']

def __setitem__(self, key, value):
self._routes[key.lower()] = value

def __delitem__(self, key):
del self._routes[key.lower()]

def __len__(self):
return len(self._routes)

def __iter__(self):
return iter(self._routes)
15 changes: 11 additions & 4 deletions examples/back_to_back/registrar.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ async def reader(peer):
print("Subscription forwarding ended!")


class Dialplan(aiosip.BaseDialplan):

async def resolve(self, *args, **kwargs):
await super().resolve(*args, **kwargs)

if kwargs['message'].method == 'SUBSCRIBE':
return on_subscribe
elif kwargs['message'].method == 'REGISTER':
return on_register


def start(app, protocol):
app.loop.run_until_complete(
app.run(
Expand All @@ -116,10 +127,6 @@ def main():

loop = asyncio.get_event_loop()
app = aiosip.Application(loop=loop)
app.dialplan.add_user('*', {
'REGISTER': on_register,
'SUBSCRIBE': on_subscribe,
})

if args.protocol == 'udp':
start(app, aiosip.UDP)
Expand Down
15 changes: 11 additions & 4 deletions examples/back_to_back/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ async def on_subscribe(request, message):
print('Subscription ended!')



class Dialplan(aiosip.BaseDialplan):

async def resolve(self, *args, **kwargs):
await super().resolve(*args, **kwargs)

if kwargs['message'].method == 'SUBSCRIBE':
return on_subscribe()


async def start(app, protocol):
await app.run(
protocol=protocol,
Expand Down Expand Up @@ -89,10 +99,7 @@ def main():
sip_config['user'] = args.user

loop = asyncio.get_event_loop()
app = aiosip.Application(loop=loop)
app.dialplan.add_user(args.user, {
'SUBSCRIBE': on_subscribe
})
app = aiosip.Application(loop=loop, dialplan=Dialplan())

if args.protocol == 'udp':
server = start(app, aiosip.UDP)
Expand Down
14 changes: 10 additions & 4 deletions examples/call/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ async def on_invite(request, message):
break


class Dialplan(aiosip.BaseDialplan):

async def resolve(self, *args, **kwargs):
await super().resolve(*args, **kwargs)

if kwargs['message'].method == 'INVITE':
return on_invite


def start(app, protocol):
app.loop.run_until_complete(
app.run(
Expand All @@ -54,10 +63,7 @@ def main():
args = parser.parse_args()

loop = asyncio.get_event_loop()
app = aiosip.Application(loop=loop)
app.dialplan.add_user('aiosip', {
'INVITE': on_invite
})
app = aiosip.Application(loop=loop, dialplan=Dialplan())

if args.protocol == 'udp':
start(app, aiosip.UDP)
Expand Down
5 changes: 0 additions & 5 deletions examples/subscribe/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
}


async def option(dialog, request):
await dialog.reply(request, status_code=200)


async def run_subscription(peer, duration):
subscription = await peer.subscribe(
from_details=aiosip.Contact.from_header('sip:{}@{}:{}'.format(
Expand Down Expand Up @@ -65,7 +61,6 @@ def main():

loop = asyncio.get_event_loop()
app = aiosip.Application(loop=loop)
app.dialplan.add_user('asterisk', option)

if args.protocol == 'udp':
loop.run_until_complete(start(app, aiosip.UDP, args.duration))
Expand Down
14 changes: 10 additions & 4 deletions examples/subscribe/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ async def on_subscribe(request, message):
print('Subscription ended!')


class Dialplan(aiosip.BaseDialplan):

async def resolve(self, *args, **kwargs):
await super().resolve(*args, **kwargs)

if kwargs['message'].method == 'SUBSCRIBE':
return on_subscribe


def start(app, protocol):
app.loop.run_until_complete(
app.run(
Expand All @@ -67,10 +76,7 @@ def main():
args = parser.parse_args()

loop = asyncio.get_event_loop()
app = aiosip.Application(loop=loop)
app.dialplan.add_user('subscriber', {
'SUBSCRIBE': on_subscribe
})
app = aiosip.Application(loop=loop, dialplan=Dialplan())

if args.protocol == 'udp':
start(app, aiosip.UDP)
Expand Down

0 comments on commit 659f010

Please sign in to comment.