diff --git a/duniterpy/api/client.py b/duniterpy/api/client.py index 4e7aea6d177071d4db1da619ca310e75803ffeb3..efffcb64c4d8719dbdbaee838b74d9ea37e08fea 100644 --- a/duniterpy/api/client.py +++ b/duniterpy/api/client.py @@ -171,6 +171,11 @@ class API(object): """ Connect to a websocket in order to use API parameters + In reality, aiohttp.session.ws_connect returns a aiohttp.client._WSRequestContextManager instance. + It must be used in a with statement to get the ClientWebSocketResponse instance from it (__aenter__). + At the end of the with statement, aiohttp.client._WSRequestContextManager.__aexit__ is called + and close the ClientWebSocketResponse in it. + :param path: the url path :rtype: aiohttp.ClientWebSocketResponse """ diff --git a/examples/request_data.py b/examples/request_data.py index e901d73a7d8311eab75099a81e04e19747a6c4ab..8603ec02a1449d6ac79e09e06d2a304231d62316 100644 --- a/examples/request_data.py +++ b/examples/request_data.py @@ -14,24 +14,28 @@ BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" async def main(): """ - Main code + Main code (synchronous requests) """ # Create Client from endpoint string in Duniter format client = Client(BMAS_ENDPOINT) # Get the node summary infos by dedicated method (with json schema validation) + print("\nCall bma.node.summary:") response = await client(bma.node.summary) print(response) # Get the money parameters located in the first block + print("\nCall bma.blockchain.parameters:") response = await client(bma.blockchain.parameters) print(response) # Get the current block + print("\nCall bma.blockchain.current:") response = await client(bma.blockchain.current) print(response) # Get the block number 10 + print("\nCall bma.blockchain.block(10):") response = await client(bma.blockchain.block, 10) print(response) @@ -59,6 +63,7 @@ async def main(): } # Get the node summary infos (direct REST GET request) + print("\nCall direct get on node/summary") response = await client.get('node/summary', rtype=RESPONSE_AIOHTTP, schema=summary_schema) print(response) diff --git a/examples/request_data_async.py b/examples/request_data_async.py new file mode 100644 index 0000000000000000000000000000000000000000..77ad4992d123964bf9580abb2a66508c9aa06667 --- /dev/null +++ b/examples/request_data_async.py @@ -0,0 +1,57 @@ +import asyncio + +from duniterpy.api import bma +from duniterpy.api.client import Client + +# CONFIG ####################################### + +# You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT] +# or the simple definition : [NAME_OF_THE_API] [DOMAIN] [PORT] +# Here we use the secure BASIC_MERKLED_API (BMAS) +BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" + + +################################################ + + +async def print_response(request): + print(await request) + + +async def main(): + """ + Main code (asynchronous requests) + + You can send one millions request with aiohttp : + + https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html + + But don't do that on one server, it's DDOS ! + + """ + # Create Client from endpoint string in Duniter format + client = Client(BMAS_ENDPOINT) + tasks = [] + + # Get the node summary infos by dedicated method (with json schema validation) + print("\nCall bma.node.summary:") + task = asyncio.ensure_future(client(bma.node.summary)) + tasks.append(task) + + # Get the money parameters located in the first block + print("\nCall bma.blockchain.parameters:") + task = asyncio.ensure_future(client(bma.blockchain.parameters)) + tasks.append(task) + + responses = await asyncio.gather(*tasks) + # you now have all response bodies in this variable + print("\nResponses:") + print(responses) + + # Close client aiohttp session + await client.close() + + +# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data. +# ( https://docs.python.org/3/library/asyncio.html ) +asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/request_web_socket_block.py b/examples/request_web_socket_block.py index f52ffb57d2325854f22d3e19c02a8d8323e968e8..6c4fe41f0807ba4e3cc023752a9805db2f916619 100644 --- a/examples/request_web_socket_block.py +++ b/examples/request_web_socket_block.py @@ -29,22 +29,36 @@ async def main(): # Create Web Socket connection on block path ws_connection = client(bma.ws.block) - # Mandatory to get the "for msg in ws" to work ! - # But it should work on the ws_connection which is a ClientWebSocketResponse object... + # From the documentation ws_connection should be a ClientWebSocketResponse object... + # # https://docs.aiohttp.org/en/stable/client_quickstart.html#websockets + # + # In reality, aiohttp.session.ws_connect() returns a aiohttp.client._WSRequestContextManager instance. + # It must be used in a with statement to get the ClientWebSocketResponse instance from it (__aenter__). + # At the end of the with statement, aiohttp.client._WSRequestContextManager.__aexit__ is called + # and close the ClientWebSocketResponse in it. + + # Mandatory to get the "for msg in ws" to work ! async with ws_connection as ws: - print("Connected successfully to block ws") + print("Connected successfully to web socket block path") + # Iterate on each message received... async for msg in ws: + # if message type is text... if msg.type == aiohttp.WSMsgType.TEXT: print("Received a block") + # Validate jsonschema and return a the json dict block_data = parse_text(msg.data, bma.ws.WS_BLOCK_SCHEMA) print(block_data) - await client.close() elif msg.type == aiohttp.WSMsgType.CLOSED: + # Connection is closed print("Web socket connection closed !") elif msg.type == aiohttp.WSMsgType.ERROR: + # Connection error print("Web socket connection error !") + # Close session + await client.close() + except (aiohttp.WSServerHandshakeError, ValueError) as e: print("Websocket block {0} : {1}".format(type(e).__name__, str(e))) except (aiohttp.ClientError, gaierror, TimeoutError) as e: @@ -53,6 +67,8 @@ async def main(): print("{:}:{:}".format(str(e.__class__.__name__), str(e))) + + # Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data. # ( https://docs.python.org/3/library/asyncio.html ) asyncio.get_event_loop().run_until_complete(main())