From 262cf36ecaf13b1b9c1013b9194d64450d0d4727 Mon Sep 17 00:00:00 2001 From: Vincent Texier <vit@free.fr> Date: Mon, 9 Jul 2018 11:36:49 +0200 Subject: [PATCH] issue #56 WIP - Add Client.post() method + update send membership example --- duniterpy/api/bma/blockchain.py | 23 ++++++------ duniterpy/api/client.py | 33 ++++++++++++++++- examples/send_membership.py | 63 ++++++++++++++++----------------- 3 files changed, 74 insertions(+), 45 deletions(-) diff --git a/duniterpy/api/bma/blockchain.py b/duniterpy/api/bma/blockchain.py index a10a6e3c..c79b8ecc 100644 --- a/duniterpy/api/bma/blockchain.py +++ b/duniterpy/api/bma/blockchain.py @@ -16,7 +16,7 @@ # Caner Candan <caner@candan.fr>, http://caner.candan.fr # vit import logging -from duniterpy.api.client import Client +from duniterpy.api.client import Client, RESPONSE_AIOHTTP logger = logging.getLogger("duniter/blockchain") @@ -323,17 +323,16 @@ async def memberships(client: Client, search: str) -> dict: return await client.get(MODULE + '/memberships/%s' % search, schema=MEMBERSHIPS_SCHEMA) -# async def membership(connection, membership): -# """ -# POST a Membership document -# -# :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance -# :param str membership: Membership signed raw document -# :rtype: aiohttp.ClientResponse -# """ -# client = API(connection, MODULE) -# -# return await client.requests_post('/membership', membership=membership) +async def membership(client: Client, _membership: str): + """ + POST a Membership document + + :param client: Client to connect to the api + :param _membership: Membership signed raw document + :rtype: aiohttp.ClientResponse + """ + return await client.post(MODULE + '/membership', {'membership': _membership}, rtype=RESPONSE_AIOHTTP) + async def current(client: Client) -> dict: """ diff --git a/duniterpy/api/client.py b/duniterpy/api/client.py index 07fb374a..19c9c4af 100644 --- a/duniterpy/api/client.py +++ b/duniterpy/api/client.py @@ -198,7 +198,7 @@ class Client: async def get(self, url_path: str, params: dict = None, rtype: str = RESPONSE_JSON, schema: dict = None)-> any: """ - Get request on self.endpoint + url_path + GET request on self.endpoint + url_path :param url_path: Url encoded path following the endpoint :param params: Url query string parameters dictionary @@ -227,6 +227,37 @@ class Client: elif rtype == RESPONSE_JSON: return await response.json() + async def post(self, url_path: str, params: dict = None, rtype: str = RESPONSE_JSON, schema: dict = None)-> any: + """ + POST request on self.endpoint + url_path + + :param url_path: Url encoded path following the endpoint + :param params: Url query string parameters dictionary + :param rtype: Response type + :param schema: Json Schema to validate response (optional, default None) + :return: + """ + if params is None: + params = dict() + + client = API(self.endpoint.conn_handler(self.session, self.proxy), '') + + # get aiohttp response + response = await client.requests_post(url_path, **params) + + # if schema supplied... + if schema is not None: + # validate response + await parse_response(response, schema) + + # return the chosen type + if rtype == RESPONSE_AIOHTTP: + return response + elif rtype == RESPONSE_TEXT: + return await response.text() + elif rtype == RESPONSE_JSON: + return await response.json() + async def close(self): """ Close aiohttp session diff --git a/examples/send_membership.py b/examples/send_membership.py index 7a85af84..26111d72 100644 --- a/examples/send_membership.py +++ b/examples/send_membership.py @@ -1,13 +1,11 @@ import asyncio -import aiohttp import getpass import duniterpy.api.bma as bma -from duniterpy.api.endpoint import SecuredBMAEndpoint +from duniterpy.api.client import Client from duniterpy.documents import BlockUID, Identity, Membership from duniterpy.key import SigningKey - # CONFIG ####################################### # You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT] @@ -15,21 +13,18 @@ from duniterpy.key import SigningKey # Here we use the secure BASIC_MERKLED_API (BMAS) BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" -################################################ -# Latest duniter-python-api is asynchronous and you have to create an aiohttp session to send request -# ( http://pythonhosted.org/aiohttp ) -AIOHTTP_SESSION = aiohttp.ClientSession() +################################################ -def get_identity_document(current_block, uid, salt, password): +def get_identity_document(current_block: dict, uid: str, salt: str, password: str) -> Identity: """ Get an Identity document - :param dict current_block: Current block data - :param str uid: Unique Identifier - :param str salt: Passphrase of the account - :param str password: Password of the account + :param current_block: Current block data + :param uid: Unique Identifier + :param salt: Passphrase of the account + :param password: Password of the account :rtype: Identity """ @@ -56,15 +51,16 @@ def get_identity_document(current_block, uid, salt, password): return identity -def get_membership_document(mtype, current_block, identity, salt, password): +def get_membership_document(membership_type: str, current_block: dict, identity: Identity, salt: str, + password: str) -> Membership: """ Get a Membership document - :param str mtype: "IN" to ask for membership or "OUT" to cancel membership - :param dict current_block: Current block data - :param Identity identity: Identity document - :param str salt: Passphrase of the account - :param str password: Password of the account + :param membership_type: "IN" to ask for membership or "OUT" to cancel membership + :param current_block: Current block data + :param identity: Identity document + :param salt: Passphrase of the account + :param password: Password of the account :rtype: Membership """ @@ -81,7 +77,7 @@ def get_membership_document(mtype, current_block, identity, salt, password): currency=current_block['currency'], issuer=key.pubkey, membership_ts=timestamp, - membership_type=mtype, + membership_type=membership_type, uid=identity.uid, identity_ts=identity.timestamp, signature=None @@ -97,11 +93,15 @@ async def main(): """ Main code """ - # connection handler from BMA endpoint - connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION) + # Create Client from endpoint string in Duniter format + client = Client(BMAS_ENDPOINT) + + # Get the node summary infos by dedicated method (with json schema validation) + response = await client(bma.node.summary) + print(response) # capture current block to get version and currency and blockstamp - current_block = await bma.blockchain.current(connection) + current_block = await client(bma.blockchain.current) # prompt hidden user entry salt = getpass.getpass("Enter your passphrase (salt): ") @@ -110,27 +110,26 @@ async def main(): password = getpass.getpass("Enter your password: ") # prompt entry - UID = input("Enter your UID: ") + uid = input("Enter your UID: ") # create our signed identity document - identity = get_identity_document(current_block, UID, salt, password) + identity = get_identity_document(current_block, uid, salt, password) # create a membership demand document membership = get_membership_document("IN", current_block, identity, salt, password) - # send the membership document to the node - response = await bma.blockchain.membership(connection, membership.signed_raw()) + # send the membership signed raw document to the node + response = await client(bma.blockchain.membership, membership.signed_raw()) if response.status == 200: print(await response.text()) else: print("Error while publishing membership : {0}".format(await response.text())) - response.close() - + # Close client aiohttp session + await client.close() -with AIOHTTP_SESSION: - # 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()) +# 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()) -- GitLab