Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
# wazo-websocketd-client

A python library to connect to wazo-websocketd.
An asyncio python3 library to connect to wazo-websocketd.


Usage:

```python
import asyncio
from wazo_websocketd_client import Client

c = Client(host, token=token, verify_certificate=False)

def callback(data):
async def callback(data):
print(data)

c.on('call_created', callback)
c.on('call_ended', callback)
async def main():
c = Client(host, token=token, verify_certificate=False)
c.on('call_created', callback)
c.on('call_ended', callback)
await c.run()

c.run()
asyncio.run(main())
```
5 changes: 5 additions & 0 deletions contribs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
git+https://github.com/wazo-platform/wazo-auth-client.git
git+https://github.com/wazo-platform/xivo-lib-python.git
git+https://github.com/wazo-platform/wazo-lib-rest-client.git
git+https://github.com/wazo-platform/wazo-websocketd-client.git@asyncio_client
websockets==8.1
34 changes: 34 additions & 0 deletions contribs/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env python3

import asyncio

from wazo_auth_client import Client as Auth
from wazo_websocketd_client import Client as WebSocket


username = ""
password = ""
host = ""

events = [
'call_created',
'call_ended'
]

def get_token():
auth = Auth(host, username=username, password=password, verify_certificate=False)
token_data = auth.token.new('wazo_user', expiration=3600)
return token_data['token']

async def callback(data):
print(data)

async def main():
token = get_token()
ws = WebSocket(host, token=token, verify_certificate=False)
for event in events:
ws.on(event, callback)

await ws.run()

asyncio.run(main())
19 changes: 3 additions & 16 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,19 @@ Maintainer: Wazo Maintainers <dev@wazo.community>
Build-Depends:
debhelper (>= 10),
dh-python,
python-all (>= 2.7),
python-setuptools,
python3-all,
python3-setuptools
Standards-Version: 4.2.1
X-Python-Version: >= 2.7
X-Python3-Version: >= 3.5

Package: wazo-websocketd-client
Architecture: all
Section: python
Depends:
${python:Depends},
${misc:Depends},
python-websocket
Description: wazo-websocketd client library - Python 2
Wazo is a system based on a powerful IPBX, to bring an easy to
install solution for telephony and related services.
X-Python3-Version: >= 3.7

Package: wazo-websocketd-client-python3
Architecture: all
Section: python
Depends:
${python3:Depends},
${misc:Depends},
python3-websocket
python3-websockets
Description: wazo-websocketd client library - Python 3
Wazo is a system based on a powerful IPBX, to bring an easy to
install solution for telephony and related services.
.
3 changes: 1 addition & 2 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
# -*- makefile -*-

export PYBUILD_NAME=wazo_websocketd_client
export PYBUILD_DESTDIR_python2=debian/wazo-websocketd-client/
export PYBUILD_DESTDIR_python3=debian/wazo-websocketd-client-python3/
export PYBUILD_DISABLE=test

%:
dh $@ --with python2,python3 --buildsystem=pybuild
dh $@ --with python3 --buildsystem=pybuild
84 changes: 37 additions & 47 deletions wazo_websocketd_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

import logging
import json
import websocket
import ssl
import asyncio
import websockets

from .exceptions import AlreadyConnectedException, NotRunningException

Expand All @@ -23,7 +25,6 @@ def __init__(
token=None,
verify_certificate=True,
wss=True,
debug=False,
**kwargs
):
self.host = host
Expand All @@ -33,9 +34,6 @@ def __init__(
self._wss = wss
self._verify_certificate = verify_certificate

if debug:
websocket.enableTrace(debug)

self._ws_app = None
self._is_running = False
self._callbacks = {}
Expand All @@ -45,47 +43,47 @@ def set_token(self, token):
raise AlreadyConnectedException()
self._token_id = token

def subscribe(self, event_name):
self._ws_app.send(
async def subscribe(self, event_name):
await self._ws_app.send(
json.dumps({'op': 'subscribe', 'data': {'event_name': event_name}})
)

def on(self, event, callback):
self._callbacks[event] = callback

def trigger_callback(self, event, data):
async def trigger_callback(self, event, data):
if '*' in self._callbacks:
self._callbacks['*'](data)
await self._callbacks['*'](data)
elif self._callbacks.get(event):
self._callbacks[event](data)
await self._callbacks[event](data)

def _start(self):
async def _start(self):
msg = {'op': 'start'}
self._ws_app.send(json.dumps(msg))
await self._ws_app.send(json.dumps(msg))

def init(self, msg):
async def init(self, msg):
if msg.get('op') == 'init':
for event in self._callbacks.keys():
self.subscribe(event)
self._start()
await self.subscribe(event)
await self._start()

if msg.get('op') == 'start':
self._is_running = True

def ping(self, payload):
async def ping(self, payload):
if not self._ws_app:
raise NotRunningException()

self._ws_app.send(json.dumps({'op': 'ping', 'data': {'payload': payload}}))
await self._ws_app.send(json.dumps({'op': 'ping', 'data': {'payload': payload}}))

def on_message(self, ws, message):
async def on_message(self, ws, message):
msg = json.loads(message)

if not self._is_running:
self.init(msg)
await self.init(msg)
else:
if msg.get('op') == 'event':
self.trigger_callback(msg['data']['name'], msg['data'])
await self.trigger_callback(msg['data']['name'], msg['data'])

def on_error(self, ws, error):
logger.error('WS encountered an error: %s: %s', type(error).__name__, error)
Expand All @@ -111,8 +109,8 @@ def on_close(self, ws, close_status_code, close_reason):
def on_open(self, ws):
logger.debug('Starting connection ...')

def update_token(self, token):
self._ws_app.send(json.dumps({'op': 'token', 'data': {'token': token}}))
async def update_token(self, token):
await self._ws_app.send(json.dumps({'op': 'token', 'data': {'token': token}}))

def url(self):
base = self._url_fmt.format(
Expand All @@ -124,36 +122,28 @@ def url(self):
return '{}/?version=2'.format(base)

def headers(self):
return ["X-Auth-Token: {}".format(self._token_id)]

def run(self):
# websocket-client doesn't play nice with methods
def on_open(ws):
self.on_open(ws)

def on_close(ws, close_status_code, close_reason):
self.on_close(ws, close_status_code, close_reason)

def on_message(ws, message):
self.on_message(ws, message)

def on_error(ws, error):
self.on_error(ws, error)
return [["X-Auth-Token", self._token_id]]

async def run(self):
try:
self._ws_app = websocket.WebSocketApp(
if not self._verify_certificate:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
else:
ssl_context = True

self._ws_app = await websockets.connect(
self.url(),
header=self.headers(),
on_message=on_message,
on_open=on_open,
on_error=on_error,
on_close=on_close,
extra_headers=self.headers(),
ssl=ssl_context
)

kwargs = {}
if not self._verify_certificate:
kwargs['sslopt'] = {'cert_reqs': False}
self._ws_app.run_forever(**kwargs)
self.on_open(self._ws_app)

while True:
msg = await self._ws_app.recv()
await self.on_message(self._ws_app, msg)

except Exception as e:
logger.error('Websocketd connection error: %s: %s', type(e).__name__, e)