From 78ad3a076b17ad167011954dec3d0964d30e1faa Mon Sep 17 00:00:00 2001 From: Marcin Debski Date: Wed, 31 Mar 2021 16:24:32 +0200 Subject: [PATCH] Proof of Concept related to async wss --- Pipfile | 1 + Pipfile.lock | 161 ++++++++++++++++----------- utils/async_ws_client.py | 228 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 327 insertions(+), 63 deletions(-) create mode 100644 utils/async_ws_client.py diff --git a/Pipfile b/Pipfile index 192e3d0..f9a2ed9 100644 --- a/Pipfile +++ b/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] requests = "2.25.1" websocket-client= "0.57.0" +websockets = "8.1" [dev-packages] pre-commit = "2.10.1" diff --git a/Pipfile.lock b/Pipfile.lock index 631bc10..4af647c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "81b1250c707aa945da880439cf8009382394c42219816859b3f750305e83d192" + "sha256": "b3d5b4eb7314125280aa16c523a7eda2664190b7f23c78635afc938e4d8c3780" }, "pipfile-spec": 6, "requires": { @@ -57,19 +57,47 @@ }, "urllib3": { "hashes": [ - "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", - "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" + "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df", + "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.3" + "version": "==1.26.4" }, "websocket-client": { "hashes": [ - "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549", - "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010" + "sha256:44b5df8f08c74c3d82d28100fdc81f4536809ce98a17f0757557813275fbb663", + "sha256:63509b41d158ae5b7f67eb4ad20fecbb4eee99434e73e140354dc3ff8e09716f" ], "index": "pypi", - "version": "==0.57.0" + "version": "==0.58.0" + }, + "websockets": { + "hashes": [ + "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5", + "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5", + "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308", + "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb", + "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a", + "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c", + "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170", + "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422", + "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8", + "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485", + "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f", + "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8", + "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc", + "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779", + "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989", + "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1", + "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092", + "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824", + "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d", + "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55", + "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36", + "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b" + ], + "index": "pypi", + "version": "==8.1" } }, "develop": { @@ -82,11 +110,11 @@ }, "astroid": { "hashes": [ - "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc", - "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d" + "sha256:6b0ed1af831570e500e2437625979eaa3b36011f66ddfc4ce930128610258ca9", + "sha256:cd80bf957c49765dce6d92c43163ff9d2abc43132ce64d4b1b47717c6d2522df" ], "markers": "python_version >= '3.6'", - "version": "==2.5.0" + "version": "==2.5.2" }, "attrs": { "hashes": [ @@ -120,19 +148,19 @@ }, "flake8": { "hashes": [ - "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839", - "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b" + "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff", + "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0" ], "index": "pypi", - "version": "==3.8.4" + "version": "==3.9.0" }, "identify": { "hashes": [ - "sha256:de7129142a5c86d75a52b96f394d94d96d497881d2aaf8eafe320cdbe8ac4bcc", - "sha256:e0dae57c0397629ce13c289f6ddde0204edf518f557bfdb1e56474aa143e77c3" + "sha256:43cb1965e84cdd247e875dec6d13332ef5be355ddc16776396d98089b9053d87", + "sha256:c7c0f590526008911ccc5ceee6ed7b085cbc92f7b6591d0ee5913a130ad64034" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.14" + "markers": "python_full_version >= '3.6.1'", + "version": "==2.2.2" }, "iniconfig": { "hashes": [ @@ -143,45 +171,44 @@ }, "isort": { "hashes": [ - "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e", - "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc" + "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6", + "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d" ], "markers": "python_version >= '3.6' and python_version < '4.0'", - "version": "==5.7.0" + "version": "==5.8.0" }, "lazy-object-proxy": { "hashes": [ - "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39", - "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694", - "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9", - "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84", - "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa", - "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128", - "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871", - "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0", - "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4", - "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302", - "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458", - "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c", - "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7", - "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb", - "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163", - "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847", - "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108", - "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef", - "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f", - "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315", - "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068", - "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166", - "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a", - "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d" + "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653", + "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61", + "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2", + "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837", + "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3", + "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43", + "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726", + "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3", + "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587", + "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8", + "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a", + "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd", + "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f", + "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad", + "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4", + "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b", + "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf", + "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981", + "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741", + "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e", + "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93", + "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.5.2" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.6.0" }, "mako": { "hashes": [ - "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab" + "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab", + "sha256:aea166356da44b9b830c8023cd9b557fa856bd8b4035d6de771ca027dfc5cc6e" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.4" @@ -291,11 +318,11 @@ }, "pre-commit": { "hashes": [ - "sha256:16212d1fde2bed88159287da88ff03796863854b04dc9f838a55979325a3d20e", - "sha256:399baf78f13f4de82a29b649afd74bef2c4e28eb4f021661fc7f29246e8c7a3a" + "sha256:94c82f1bf5899d56edb1d926732f4e75a7df29a0c8c092559c77420c9d62428b", + "sha256:de55c5c72ce80d79106e48beb1b54104d16495ce7f95b0c7b13d4784193a00af" ], "index": "pypi", - "version": "==2.10.1" + "version": "==2.11.1" }, "py": { "hashes": [ @@ -307,27 +334,27 @@ }, "pycodestyle": { "hashes": [ - "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", - "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" + "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", + "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.6.0" + "version": "==2.7.0" }, "pyflakes": { "hashes": [ - "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", - "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" + "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", + "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.2.0" + "version": "==2.3.1" }, "pylint": { "hashes": [ - "sha256:81ce108f6342421169ea039ff1f528208c99d2e5a9c4ca95cfc5291be6dfd982", - "sha256:a251b238db462b71d25948f940568bb5b3ae0e37dbaa05e10523f54f83e6cc7e" + "sha256:209d712ec870a0182df034ae19f347e725c1e615b2269519ab58a35b3fcbbe7a", + "sha256:bd38914c7731cdc518634a8d3c5585951302b6e2b6de60fbb3f7a0220e21eeee" ], "index": "pypi", - "version": "==2.7.1" + "version": "==2.7.4" }, "pyparsing": { "hashes": [ @@ -359,15 +386,23 @@ "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", + "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", + "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", + "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", + "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", + "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", - "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc" + "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", + "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", + "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", + "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==5.4.1" @@ -390,11 +425,11 @@ }, "virtualenv": { "hashes": [ - "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d", - "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3" + "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107", + "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.4.2" + "version": "==20.4.3" }, "wrapt": { "hashes": [ diff --git a/utils/async_ws_client.py b/utils/async_ws_client.py new file mode 100644 index 0000000..e7d0a26 --- /dev/null +++ b/utils/async_ws_client.py @@ -0,0 +1,228 @@ +''' +Async client for WebSocket connections. +''' + +# pylint: disable=R1702 + +import asyncio +import json +import logging +from abc import ABCMeta + +import websockets +from websockets import WebSocketException + + +def parse_url_and_return_origin(url: str) -> str: + ''' Parse url and return correct origin. + + Args: + url (str): String which defines environment. + + Returns: + str: String with correct origin depends on environment. + ''' + domain = 'livechatinc.com' + if 'labs' in url: + return f'https://secure.labs.{domain}' + if 'staging' in url: + return f'https://secure-lc.{domain}' + return f'https://secure.{domain}' + + +def prepare_payload(parameters: dict) -> dict: + ''' Prepares payload for request based on provided parameters by removing + unnecessary or protected variables and removing `None` values. Please + note that main use is to pass `locals()` as `parameters`. + + Args: + parameters (dict): parameters provided as key -> value pairs. + + Returns: + dict: payload object without unnecessary items to be used in requests. + ''' + return { + key: value + for key, value in parameters.items() + if key not in ['self', 'payload'] and value is not None + } + + +class AsyncWebsocketClient: + ''' WebSocket asynchronous client based on websockets module. ''' + def __init__(self, url: str): + self.url = url + self.websocket = None + self.keep_alive = True + logging.basicConfig() + self.logger = logging.getLogger() + self.logger.setLevel(logging.INFO) + + async def open(self, keep_alive: bool = True) -> None: + ''' Open WebSocket connection. + Args: + keep_alive(bool): Bool which states if connection should be kept, by default sets to `True`. + ''' + try: + self.websocket = await websockets.connect(self.url) + except WebSocketException as exception: + self.logger.critical(f'WebSocket Exception: {exception}') + else: + if keep_alive: + self.keep_alive = True + asyncio.ensure_future(self._keep_ws_alive()) + + async def close(self) -> None: + ''' Close WebSocket connection. ''' + if self.websocket is not None: + await self.websocket.close() + self.websocket = None + self.keep_alive = False + + async def send(self, request: dict) -> None: + ''' Send request via WebSocket. + Args: + request (dict): Dictionary which is being converted to payload. + ''' + if self.websocket is not None: + await self.websocket.send(json.dumps(request)) + + async def receive(self) -> dict: + ''' Receive data from WebSocket. + Returns: + dict: Dictionary containing response from WebSocket. + ''' + if self.websocket is not None: + results = await self.websocket.recv() + return json.loads(results) + + async def _keep_ws_alive(self, interval: int = 10) -> None: + ''' Ping WebSocket connection to keep it alive. ''' + while self.keep_alive: + if self.websocket: + try: + await self.websocket.send( + json.dumps({ + 'action': 'ping', + 'payload': {} + }, indent=4)) + except WebSocketException as exception: + self.logger.critical( + f'Exception caught while pinging the WebSocket: {exception}.' + ) + break + else: + self.logger.info('Ping action sent.') + await asyncio.sleep(interval) + + +class AsyncMetaClass: + ''' + Allows to define an async __init__. + ''' + async def __new__(cls, *args, **kwargs): + instance = super().__new__(cls) + await instance.__init__(*args, **kwargs) + return instance + + async def __init__(self): + pass + + +class AgentRTM: + ''' Main class that gets specific client. ''' + @staticmethod + def get_client(version: str = '3.3', + base_url: str = 'api.livechatinc.com'): + ''' Returns client for specific Agent RTM version. + + Args: + version (str): API's version. Defaults to `3.3`. + base_url (str): API's base url. Defaults to `api.livechatinc.com`. + + Returns: + AgentRTMInterface: API client object for specified version. + + Raises: + ValueError: If the specified version does not exist. + ''' + client = {'3.3': AgentRTM33(version, base_url)}.get(version) + if not client: + raise ValueError('Provided version does not exist.') + return client + + +class AgentRTMInterface(AsyncMetaClass, metaclass=ABCMeta): + ''' AgentRTM interface class. ''' + async def __init__(self, version: str, url: str): + self.ws = AsyncWebsocketClient( + url=f'wss://{url}/v{version}/agent/rtm/ws') + await self.open_connection() + + async def open_connection(self) -> None: + ''' Opens WebSocket connection. ''' + await self.ws.open() + + async def close_connection(self) -> None: + ''' Closes WebSocket connection. ''' + await self.ws.close() + + async def receive_message(self) -> dict: + ''' Receive message from WebSocket. ''' + return await self.ws.receive() + + async def login(self, + token: str = None, + timezone: str = None, + reconnect: bool = None, + push_notifications: dict = None, + application: dict = None, + away: bool = None, + customer_push_level: str = None, + payload: dict = None) -> None: + ''' Logs in agent. + + Args: + token (str): OAuth token from the Agent's account. + timezone (str): Agent's timezone. + reconnect (bool): Reconnecting sets the status to the + last known state instead of the default one. + push_notifications (dict): Push notifications for the requested token. + application (dict): Object containing information related to + the application's name and version. + away (bool): When True, the connection is set to the away state. + Defaults to False. + customer_push_level (str): Possible values: my, engaged, online. + Defaults to my if login creates the first session; + otherwise it preserves the current customer_push_level. + payload (dict): Custom payload to be used as request's data. + It overrides all other parameters provided for the method. + ''' + if payload is None: + payload = prepare_payload(locals()) + await self.ws.send({'action': 'login', 'payload': payload}) + ''' + Of course, it's possible to return response and pushes related to the particular request, + but the question is - do we need this, having async world? + ''' + + +class AgentRTM33(AgentRTMInterface): + ''' AgentRTM version 3.3 class. ''' + + +async def main(): + ''' Just main coroutine. ''' + client = await AgentRTM.get_client(base_url='api.labs.livechatinc.com') + await asyncio.sleep(1) + await client.login(token='Bearer fra-a:gYKvakQNfRUMaajMiwnFHWeXEpg') + await asyncio.sleep(1) + print(await client.receive_message()) + print(await client.receive_message()) + print(await client.receive_message()) + print('The End') + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main())