Skip to content

Commit

Permalink
Callbacks 4 Dayz (#29)
Browse files Browse the repository at this point in the history
- Compatibility with recent aws-c-mqtt API changes (interruption callbacks, etc)
- Functions that had completion-callbacks now return Futures instead.
- Use Python-3-style enums.
- Update aws-c-common, aws-c-io, aws-c-mqtt, s2n dependencies
- Scrubbed over mqtt_client_connection.c, being more careful about refcounts and error-handling.
  • Loading branch information
ColdenCullen authored and graebm committed Jan 16, 2019
1 parent 2f59cdf commit 61cecbe
Show file tree
Hide file tree
Showing 20 changed files with 611 additions and 283 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ __pycache__/
# Distribution / packaging
.Python
build/
deps_build/
develop-eggs/
dist/
downloads/
Expand Down
2 changes: 1 addition & 1 deletion aws-c-io
28 changes: 14 additions & 14 deletions aws_crt/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,43 @@
# permissions and limitations under the License.

import _aws_crt_python
from enum import IntEnum

def is_alpn_available():
return _aws_crt_python.aws_py_is_alpn_available()

class EventLoopGroup(object):
__slots__ = ['_internal_elg']
__slots__ = ('_internal_elg')

def __init__(self, num_threads):
self._internal_elg = _aws_crt_python.aws_py_io_event_loop_group_new(num_threads)

class ClientBootstrap(object):
__slots__ = ['elg', '_internal_bootstrap']
__slots__ = ('elg', '_internal_bootstrap')

def __init__(self, elg):
assert isinstance(elg, EventLoopGroup)

self.elg = elg
self._internal_bootstrap = _aws_crt_python.aws_py_io_client_bootstrap_new(self.elg._internal_elg)

TlsVersion = type('TlsVersion', (), dict(
SSLv3 = 0,
TLSV1 = 1,
TLSV1_1 = 2,
TLSV1_2 = 3,
TLSV1_3 = 4,
Default = 128,
))
class TlsVersion(IntEnum):
SSLv3 = 0
TLSv1 = 1
TLSv1_1 = 2
TLSv1_2 = 3
TLSv1_3 = 4
DEFAULT = 128

class TlsContextOptions(object):
__slots__ = ['min_tls_ver', 'ca_file', 'ca_path', 'alpn_list', 'certificate_path', 'private_key_path', 'pkcs12_path', 'pkcs12_password', 'verify_peer']
__slots__ = ('min_tls_ver', 'ca_file', 'ca_path', 'alpn_list', 'certificate_path', 'private_key_path', 'pkcs12_path', 'pkcs12_password', 'verify_peer')

def __init__(self):

for slot in self.__slots__:
setattr(self, slot, None)

self.min_tls_ver = TlsVersion.Default
self.min_tls_ver = TlsVersion.DEFAULT

def override_default_trust_store(self, ca_path, ca_file):

Expand Down Expand Up @@ -107,14 +107,14 @@ def create_server_with_mtls_pkcs12(clazz, pkcs12_path, pkcs12_password):
return opt

class ClientTlsContext(object):
__slots__ = ['options', '_internal_tls_ctx']
__slots__ = ('options', '_internal_tls_ctx')

def __init__(self, options):
assert isinstance(options, TlsContextOptions)

self.options = options
self._internal_tls_ctx = _aws_crt_python.aws_py_io_client_tls_ctx_new(
options.min_tls_ver,
options.min_tls_ver.value,
options.ca_file,
options.ca_path,
options.alpn_list,
Expand Down
196 changes: 152 additions & 44 deletions aws_crt/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,26 @@
# permissions and limitations under the License.

import _aws_crt_python
from concurrent.futures import Future
from enum import IntEnum
from aws_crt.io import ClientBootstrap, ClientTlsContext

def _default_on_connect(return_code, session_present):
pass
def _default_on_disconnect(return_code):
return False
class QoS(IntEnum):
"""Quality of Service"""
AT_MOST_ONCE = 0
AT_LEAST_ONCE = 1
EXACTLY_ONCE = 2

QoS = type('QoS', (), dict(
AtMostOnce = 0,
AtLeastOnce = 1,
ExactlyOnce = 2,
))
class ConnectReturnCode(IntEnum):
ACCEPTED = 0
UNACCEPTABLE_PROTOCOL_VERSION = 1
IDENTIFIER_REJECTED = 2
SERVER_UNAVAILABLE = 3
BAD_USERNAME_OR_PASSWORD = 4
NOT_AUTHORIZED = 5

class Will(object):
__slots__ = ['topic', 'qos', 'payload', 'retain']
__slots__ = ('topic', 'qos', 'payload', 'retain')

def __init__(self, topic, qos, payload, retain):
self.topic = topic
Expand All @@ -35,7 +40,7 @@ def __init__(self, topic, qos, payload, retain):
self.retain = retain

class Client(object):
__slots__ = ['_internal_client', 'bootstrap', 'tls_ctx']
__slots__ = ('_internal_client', 'bootstrap', 'tls_ctx')

def __init__(self, bootstrap, tls_ctx = None):
assert isinstance(bootstrap, ClientBootstrap)
Expand All @@ -46,51 +51,154 @@ def __init__(self, bootstrap, tls_ctx = None):
self._internal_client = _aws_crt_python.aws_py_mqtt_client_new(self.bootstrap._internal_bootstrap)

class Connection(object):
__slots__ = ['_internal_connection']
__slots__ = ('_internal_connection', 'client')

def __init__(self,
client,
on_connection_interrupted=None,
on_connection_resumed=None,
reconnect_min_timeout_sec=5.0,
reconnect_max_timeout_sec=60.0):
"""
on_connection_interrupted: optional callback, with signature (error_code)
on_connection_resumed: optional callback, with signature (error_code, session_present)
"""

def __init__(self, client, client_id,
assert isinstance(client, Client)
self.client = client

self._internal_connection = _aws_crt_python.aws_py_mqtt_client_connection_new(
client._internal_client,
on_connection_interrupted,
on_connection_resumed,
)

def connect(self,
client_id,
host_name, port,
on_connect=_default_on_connect,
on_disconnect=_default_on_disconnect,
use_websocket=False, alpn=None,
use_websocket=False,
clean_session=True, keep_alive=0,
will=None,
username=None, password=None):
username=None, password=None,
connect_timeout_sec=5.0):

future = Future()

def on_connect(error_code, return_code, session_present):
if error_code == 0 and return_code == 0:
future.set_result(dict(session_present=session_present))
else:
future.set_exception(Exception("Error during connect."))

try:
assert will is None or isinstance(will, Will)
assert use_websocket == False

tls_ctx_cap = None
if self.client.tls_ctx:
tls_ctx_cap = self.client.tls_ctx._internal_tls_ctx

_aws_crt_python.aws_py_mqtt_client_connection_connect(
self._internal_connection,
client_id,
host_name,
port,
tls_ctx_cap,
keep_alive,
will,
username,
password,
on_connect,
)

except Exception as e:
future.set_exception(e)

return future

def reconnect(self):
future = Future()

def on_connect(error_code, return_code, session_present):
if error_code == 0 and return_code == 0:
future.set_result(dict(session_present=session_present))
else:
future.set_exception(Exception("Error during reconnect"))

try:
_aws_crt_python.aws_py_mqtt_client_connection_reconnect(self._internal_connection, on_connect)
except Exception as e:
future.set_exception(e)

return future

assert isinstance(client, Client)
assert will is None or isinstance(will, Will)
def disconnect(self):

assert use_websocket == False
future = Future()

tls_ctx_cap = None
if client.tls_ctx:
tls_ctx_cap = client.tls_ctx._internal_tls_ctx
def on_disconnect():
future.set_result(dict())

self._internal_connection = _aws_crt_python.aws_py_mqtt_client_connection_new(
client._internal_client,
tls_ctx_cap,
host_name,
port,
client_id,
keep_alive,
on_connect,
on_disconnect,
will,
username,
password,
)
try:
_aws_crt_python.aws_py_mqtt_client_connection_disconnect(self._internal_connection, on_disconnect)
except Exception as e:
future.set_exception(e)

def disconnect(self):
_aws_crt_python.aws_py_mqtt_client_connection_disconnect(self._internal_connection)
return future

def subscribe(self, topic, qos, callback):
"""
callback: callback with signature (topic, message)
"""
future = Future()
packet_id = 0

def suback(packet_id, topic, qos):
future.set_result(dict(
packet_id=packet_id,
topic=topic,
qos=QoS(qos),
))

try:
packet_id = _aws_crt_python.aws_py_mqtt_client_connection_subscribe(self._internal_connection, topic, qos.value, callback, suback)
except Exception as e:
future.set_exception(e)

return future, packet_id

def unsubscribe(self, topic):
future = Future()
packet_id = 0

def unsuback(packet_id):
future.set_result(dict(
packet_id=packet_id
))

try:
packet_id = _aws_crt_python.aws_py_mqtt_client_connection_unsubscribe(self._internal_connection, topic, unsuback)

except Exception as e:
future.set_exception(e)

return future, packet_id

def publish(self, topic, payload, qos, retain=False):
future = Future()
packet_id = 0

def subscribe(self, topic, qos, callback, suback_callback=None):
return _aws_crt_python.aws_py_mqtt_client_connection_subscribe(self._internal_connection, topic, qos, callback, suback_callback)
def puback(packet_id):
future.set_result(dict(
packet_id=packet_id
))

def unsubscribe(self, topic, unsuback_callback=None):
return _aws_crt_python.aws_py_mqtt_client_connection_unsubscribe(self._internal_connection, topic, unsuback_callback)
try:
packet_id = _aws_crt_python.aws_py_mqtt_client_connection_publish(self._internal_connection, topic, payload, qos.value, retain, puback)
except Exception as e:
future.set_exception(e)

def publish(self, topic, payload, qos, retain=False, puback_callback=None):
return _aws_crt_python.aws_py_mqtt_client_connection_publish(self._internal_connection, topic, payload, qos, retain, puback_callback)
return future, packet_id

def ping(self):
_aws_crt_python.aws_py_mqtt_client_connection_ping(self._internal_connection)
1 change: 0 additions & 1 deletion codebuild/common-macos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ function install_from_brew {

install_from_brew openssl
install_from_brew gdbm
install_from_brew sqlite
install_from_brew python

git submodule update --init --recursive
Expand Down
3 changes: 2 additions & 1 deletion codebuild/linux-clang3-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ phases:
commands:
- sudo apt-get update -y
- sudo apt-get update
- sudo apt-get install clang-3.9 cmake3 cppcheck clang-tidy-3.9 python3 python3-dev python3-setuptools ninja-build libssl-dev -y
- sudo apt-get install clang-3.9 cmake3 cppcheck clang-tidy-3.9 python3 python3-dev python3-pip ninja-build libssl-dev -y
- pip3 install --upgrade setuptools
pre_build:
commands:
- export CC=clang-3.9
Expand Down
4 changes: 2 additions & 2 deletions codebuild/linux-clang6-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ phases:
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test
- sudo apt-add-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main"
- sudo apt-get update -y
- sudo apt-get install clang-6.0 cmake3 cppcheck clang-tidy-6.0 clang-format-6.0 python3 python3-dev python3-setuptools ninja-build libssl-dev -y -f --force-yes

- sudo apt-get install clang-6.0 cmake3 cppcheck clang-tidy-6.0 clang-format-6.0 python3 python3-dev python3-pip ninja-build libssl-dev -y -f --force-yes
- pip3 install --upgrade setuptools
pre_build:
commands:
- export CC=clang-6.0
Expand Down
3 changes: 2 additions & 1 deletion codebuild/linux-gcc-4x-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ phases:
install:
commands:
- sudo apt-get update -y
- sudo apt-get install gcc cmake3 cppcheck python3 python3-dev python3-setuptools ninja-build libssl-dev -y
- sudo apt-get install gcc cmake3 cppcheck python3 python3-dev python3-pip ninja-build libssl-dev -y
- pip3 install --upgrade setuptools
pre_build:
commands:
- export CC=gcc
Expand Down
3 changes: 2 additions & 1 deletion codebuild/linux-gcc-5x-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ phases:
commands:
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test
- sudo apt-get update -y
- sudo apt-get install gcc-5 cmake3 cppcheck python3 python3-dev python3-setuptools ninja-build libssl-dev -y
- sudo apt-get install gcc-5 cmake3 cppcheck python3 python3-dev python3-pip ninja-build libssl-dev -y
- pip3 install --upgrade setuptools
pre_build:
commands:
- export CC=gcc-5
Expand Down
3 changes: 2 additions & 1 deletion codebuild/linux-gcc-6x-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ phases:
commands:
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test
- sudo apt-get update -y
- sudo apt-get install gcc-6 cmake3 cppcheck python3 python3-dev python3-setuptools ninja-build libssl-dev -y -f --force-yes
- sudo apt-get install gcc-6 cmake3 cppcheck python3 python3-dev python3-pip ninja-build libssl-dev -y -f --force-yes
- pip3 install --upgrade setuptools
pre_build:
commands:
- export CC=gcc-6
Expand Down
3 changes: 2 additions & 1 deletion codebuild/linux-gcc-7x-x64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ phases:
commands:
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test
- sudo apt-get update -y
- sudo apt-get install gcc-7 cmake3 cppcheck python3 python3-dev python3-setuptools ninja-build libssl-dev -y
- sudo apt-get install gcc-7 cmake3 cppcheck python3 python3-dev python3-pip ninja-build libssl-dev -y
- pip3 install --upgrade setuptools
pre_build:
commands:
- export CC=gcc-7
Expand Down
2 changes: 1 addition & 1 deletion s2n
Submodule s2n updated from 2b418c to 383586
Loading

0 comments on commit 61cecbe

Please sign in to comment.