diff --git a/duniterpy/api/bma/__init__.py b/duniterpy/api/bma/__init__.py index 727c52b784cda73e4125b650aca550efc994295d..a1fae4d59a6566eee67a0f6c358ccace21773efc 100644 --- a/duniterpy/api/bma/__init__.py +++ b/duniterpy/api/bma/__init__.py @@ -15,16 +15,12 @@ # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr # Inso <insomniak.fr at gmail.com> +import logging +from . import network, blockchain, tx, wot, node, ud, ws - -__all__ = ['api'] +__all__ = [network, blockchain, tx, wot, node, ud, ws] PROTOCOL_VERSION = 2 -import logging - logger = logging.getLogger("duniter") - -from .api import API, ConnectionHandler, parse_error, parse_response, parse_text -from . import network, blockchain, tx, wot, node, ud, ws diff --git a/duniterpy/api/bma/blockchain.py b/duniterpy/api/bma/blockchain.py index a3a6d4bcafedfd08783535042e386a5cf34021f2..a10a6e3ca896099245ab1fe5613bb8a9c5add7e5 100644 --- a/duniterpy/api/bma/blockchain.py +++ b/duniterpy/api/bma/blockchain.py @@ -14,13 +14,13 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from duniterpy.api.bma import API, logging, parse_response +# vit +import logging +from duniterpy.api.client import Client logger = logging.getLogger("duniter/blockchain") -URL_PATH = 'blockchain' +MODULE = 'blockchain' BLOCK_SCHEMA = { "type": "object", @@ -235,8 +235,8 @@ PARAMETERS_SCHEMA = { "type": "number" } }, - "required": ["currency", "c", "dt", "ud0","sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock", - "sigWindow", "msValidity","stepMax", "medianTimeBlocks", + "required": ["currency", "c", "dt", "ud0", "sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock", + "sigWindow", "msValidity", "stepMax", "medianTimeBlocks", "avgGenTime", "dtDiffEval", "percentRot", "udTime0", "udReevalTime0", "dtReeval"] } @@ -302,196 +302,170 @@ HARDSHIP_SCHEMA = { } -async def parameters(connection): +async def parameters(client: Client) -> dict: """ GET the blockchain parameters used by this node - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ - client = API(connection, URL_PATH) - r = await client.requests_get('/parameters') - return await parse_response(r, PARAMETERS_SCHEMA) + return await client.get(MODULE + '/parameters', schema=PARAMETERS_SCHEMA) + -async def memberships(connection, search): +async def memberships(client: Client, search: str) -> dict: """ GET list of Membership documents for UID/Public key - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str search: UID/Public key + :param client: Client to connect to the api + :param search: UID/Public key :rtype: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/memberships/%s' % search, schema=MEMBERSHIPS_SCHEMA) - r = await client.requests_get('/memberships/%s' % search) - return await parse_response(r, MEMBERSHIPS_SCHEMA) -async def membership(connection, membership): +# 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 current(client: Client) -> dict: """ - POST a Membership document + GET, return last accepted block - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str membership: Membership signed raw document - :rtype: aiohttp.ClientResponse + :param client: Client to connect to the api + :rtype: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/current', schema=BLOCK_SCHEMA) - return await client.requests_post('/membership', membership=membership) -async def block(connection, number=0, block=None, signature=None): +async def block(client: Client, number: int = 0, _block: dict = None, signature: str = None): """ GET/POST a block from/to the blockchain - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param int number: Block number to get - :param dict block: Block document to post + :param client: Client to connect to the api + :param number: Block number to get + :param dict _block: Block document to post :param str signature: Signature of the block document issuer :rtype: dict """ - client = API(connection, URL_PATH) - # POST block - if block is not None and signature is not None: - return await client.requests_post('/block', block=block, signature=signature) + # client = API(connection, MODULE) + # # POST block + # if _block is not None and signature is not None: + # return await client.requests_post('/block', block=_block, signature=signature) # GET block - r = await client.requests_get('/block/%d' % number) - data = await parse_response(r, BLOCK_SCHEMA) - return data - -async def current(connection): - """ - GET, return last accepted block + return await client.get(MODULE + '/block/%d' % number, schema=BLOCK_SCHEMA) - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :rtype: dict - """ - - client = API(connection, URL_PATH) - r = await client.requests_get('/current') - return await parse_response(r, BLOCK_SCHEMA) - - -async def blocks(connection, count, start): +async def blocks(client: Client, count: int, start: int) -> list: """ GET list of blocks from the blockchain - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param int count: Number of blocks - :param int start: First block number + :param client: Client to connect to the api + :param count: Number of blocks + :param start: First block number :rtype: list """ - - client = API(connection, URL_PATH) assert type(count) is int assert type(start) is int - r = await client.requests_get('/blocks/%d/%d' % (count, start)) - return await parse_response(r, BLOCKS_SCHEMA) -async def hardship(connection, pubkey): + return await client.get(MODULE + '/blocks/%d/%d' % (count, start), schema=BLOCKS_SCHEMA) + + +async def hardship(client: Client, pubkey: str) -> dict: """ GET hardship level for given member's public key for writing next block - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str pubkey: Public key of the member + :param client: Client to connect to the api + :param pubkey: Public key of the member :rtype: dict """ - client = API(connection, URL_PATH) - r = await client.requests_get('/hardship/%s' % pubkey) - return await parse_response(r, HARDSHIP_SCHEMA) + return await client.get(MODULE + '/hardship/%s' % pubkey, schema=HARDSHIP_SCHEMA) + -async def newcomers(connection): +async def newcomers(client: Client) -> dict: """ GET, return block numbers containing newcomers - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/with/newcomers', schema=BLOCK_NUMBERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/with/newcomers') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) -async def certifications(connection): +async def certifications(client: Client) -> dict: """ GET, return block numbers containing certifications - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/with/certs', schema=BLOCK_NUMBERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/with/certs') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) -async def joiners(connection): +async def joiners(client: Client) -> dict: """ GET, return block numbers containing joiners - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/with/joiners', schema=BLOCK_NUMBERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/with/joiners') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) -async def actives(connection): +async def actives(client: Client) -> dict: """ GET, return block numbers containing actives - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/with/actives', schema=BLOCK_NUMBERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/with/actives') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) -async def leavers(connection): +async def leavers(client: Client) -> dict: """ GET, return block numbers containing leavers - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/with/leavers', schema=BLOCK_NUMBERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/with/leavers') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) -async def excluded(connection): +async def excluded(client: Client) -> dict: """ GET, return block numbers containing excluded - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/with/excluded', schema=BLOCK_NUMBERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/with/excluded') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) -async def ud(connection): +async def ud(client: Client) -> dict: """ GET, return block numbers containing universal dividend - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ - client = API(connection, URL_PATH) - r = await client.requests_get('/with/ud') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) + return await client.get(MODULE + '/with/ud', schema=BLOCK_NUMBERS_SCHEMA) -async def tx(connection): + +async def tx(client: Client) -> dict: """ GET, return block numbers containing transactions - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ - - client = API(connection, URL_PATH) - r = await client.requests_get('/with/tx') - return await parse_response(r, BLOCK_NUMBERS_SCHEMA) + return await client.get(MODULE + '/with/tx', schema=BLOCK_NUMBERS_SCHEMA) diff --git a/duniterpy/api/bma/network.py b/duniterpy/api/bma/network.py index d02b22e1a22c6988c1a286fc265034cbad9d89c1..eedaaecc3b86609ea0a2d70561e114fd53171905 100644 --- a/duniterpy/api/bma/network.py +++ b/duniterpy/api/bma/network.py @@ -14,13 +14,14 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from duniterpy.api.bma import API, logging, parse_response +# vit +import logging +from duniterpy.api.client import Client +from duniterpy.documents.peer import Peer logger = logging.getLogger("duniter/network") -URL_PATH = 'network' +MODULE = 'network' PEERING_SCHEMA = { "type": "object", @@ -100,91 +101,42 @@ PEERS_SCHEMA = schema = { ] } -async def peering(connection): + +async def peering(client: Client) -> dict: """ GET peering information about a peer - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ + return await client.get(MODULE + '/peering', schema=PEERING_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_get('/peering') - return await parse_response(r, PEERING_SCHEMA) -async def peers(connection, leaves=False, leaf=""): +async def peers(client: Client, leaves: bool = False, leaf: str = ""): """ GET peering entries of every node inside the currency network - :param bool leaves: True if leaves should be requested - :param str leaf: True if leaf should be requested + :param client: Client to connect to the api + :param leaves: True if leaves should be requested + :param leaf: True if leaf should be requested :rtype: dict """ - - client = API(connection, URL_PATH) - # GET Peers - if leaves: - r = await client.requests_get('/peering/peers', leaves=leaves) + if leaves is True: + return await client.get(MODULE + '/peering/peers', {"leaves": "true"}, schema=PEERS_SCHEMA) else: - r = await client.requests_get('/peering/peers', leaf=leaf) - - return await parse_response(r, PEERS_SCHEMA) - -async def peer(connection, entry=None, signature=None): - """ - GET peering entries of every node inside the currency network - - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param duniterpy.documents.peer.Peer entry: Peer document - :param str signature: Signature of the document issuer - :rtype: dict - """ + return await client.get(MODULE + '/peering/peers', {"leaf": leaf}, schema=PEERS_SCHEMA) - client = API(connection, URL_PATH) - r = await client.requests_post('/peering/peers', entry=entry, signature=signature) - return r -WS2P_HEADS_SCHEMA = { - "type": "object", - "properties": { - "heads": { - "type": "array", - "items": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "sig": { - "type": "string", - }, - "messageV2": { - "type": "string" - }, - "sigV2": { - "type": "string", - }, - "step": { - "type": "number", - }, - }, - "required": ["message", "sig"] - } - } - }, - "required": ["heads"] - } - - -async def heads(connection): - """ - GET Certification data over a member - - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :rtype: dict - """ - - client = API(connection, URL_PATH) - - r = await client.requests_get('/ws2p/heads') - return await parse_response(r, WS2P_HEADS_SCHEMA) +# async def peer(client: Client, entry: Peer = None, signature: str = None) -> dict: +# """ +# POST a Peer document with his signature +# +# :param client: Client to connect to the api +# :param entry: Peer document +# :param signature: Signature of the document issuer +# :rtype: dict +# """ +# +# client = API(connection, MODULE) +# r = await client.requests_post('/peering/peers', entry=entry, signature=signature) +# return r diff --git a/duniterpy/api/bma/node.py b/duniterpy/api/bma/node.py index c6b26411af8b4a047ae0d2fa8e57bad2df77f0bf..b3a630f5c0064865257600358fedfe75f1b8d1e5 100644 --- a/duniterpy/api/bma/node.py +++ b/duniterpy/api/bma/node.py @@ -14,19 +14,20 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from duniterpy.api.bma import API, logging, parse_response +# vit +import logging +from duniterpy.api.client import Client logger = logging.getLogger("duniter/node") -URL_PATH = 'node' +MODULE = 'node' + -async def summary(connection): +async def summary(client: Client) -> dict: """ - GET Certification data over a member + GET Duniter node version and infos - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ schema = { @@ -36,7 +37,7 @@ async def summary(connection): "type": "object", "properties": { "software": { - "type": "string" + "type": "string" }, "version": { "type": "string", @@ -50,7 +51,5 @@ async def summary(connection): }, "required": ["duniter"] } - client = API(connection, URL_PATH) - r = await client.requests_get('/summary') - return await parse_response(r, schema) + return await client.get(MODULE + '/summary', schema=schema) diff --git a/duniterpy/api/bma/tx.py b/duniterpy/api/bma/tx.py index 046c70529ba07554ad2dcf42b63cb866e91a5527..dfeae4170e38cf0e6b1040962380aecc44423abe 100644 --- a/duniterpy/api/bma/tx.py +++ b/duniterpy/api/bma/tx.py @@ -14,13 +14,14 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from duniterpy.api.bma import API, logging, parse_response +# vit +import logging +from duniterpy.api.client import Client +from duniterpy.documents import Transaction logger = logging.getLogger("duniter/tx") -URL_PATH = 'tx' +MODULE = 'tx' HISTORY_SCHEMA = { "type": "object", @@ -160,109 +161,100 @@ HISTORY_SCHEMA = { } SOURCES_SCHEMA = { - "type": "object", - "properties": { - "currency": { - "type": "string" - }, - "pubkey": { - "type": "string" - }, - "sources": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "noffset": { - "type": "number" - }, - "identifier": { - "type": "string" - }, - "amount": { - "type": "number" - }, - "base": { - "type": "number" - } + "type": "object", + "properties": { + "currency": { + "type": "string" + }, + "pubkey": { + "type": "string" + }, + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "noffset": { + "type": "number" + }, + "identifier": { + "type": "string" }, - "required": ["type", "noffset", "identifier", "amount", "base"] - } + "amount": { + "type": "number" + }, + "base": { + "type": "number" + } + }, + "required": ["type", "noffset", "identifier", "amount", "base"] } - }, - "required": ["currency", "pubkey", "sources"] - } + } + }, + "required": ["currency", "pubkey", "sources"] +} + -async def history(connection, pubkey): +async def history(client: Client, pubkey: str) -> dict: """ Get transactions history of public key - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str pubkey: Public key + :param client: Client to connect to the api + :param pubkey: Public key :rtype: dict """ + return await client.get(MODULE + '/history/%s' % pubkey, schema=HISTORY_SCHEMA) - client = API(connection, URL_PATH) - - r = await client.requests_get( '/history/%s' % pubkey) - return await parse_response(r, HISTORY_SCHEMA) - -async def process(connection, transaction): - """ - POST a transaction - - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param duniterpy.documents.Transaction transaction: Transaction document - :rtype: aiohttp.ClientResponse - """ - client = API(connection, URL_PATH) - r = await client.requests_post('/process', transaction=transaction) - return r +# async def process(client: Client, transaction: Transaction): +# """ +# POST a transaction +# +# :param client: Client to connect to the api +# :param transaction: Transaction document +# :rtype: aiohttp.ClientResponse +# """ +# client = API(connection, MODULE) +# +# r = await client.requests_post('/process', transaction=transaction) +# return r -async def sources(connection, pubkey): +async def sources(client: Client, pubkey: str): """ GET transaction sources - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str pubkey: Public key + :param client: Client to connect to the api + :param pubkey: Public key :rtype: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/sources/%s' % pubkey, schema=SOURCES_SCHEMA) - r = await client.requests_get( '/sources/%s' % pubkey) - return await parse_response(r, SOURCES_SCHEMA) -async def blocks(connection, pubkey, start, end): +async def blocks(client: Client, pubkey: str, start: int, end: int) -> dict: """ GET public key transactions history between start and end block number - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str pubkey: Public key - :param int start: Start from block number - :param int end: End to block number + :param client: Client to connect to the api + :param pubkey: Public key + :param start: Start from block number + :param end: End to block number :return: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/history/%s/blocks/%s/%s' % (pubkey, start, end), schema=HISTORY_SCHEMA) - r = await client.requests_get('/history/%s/blocks/%s/%s' % (pubkey, start, end)) - return await parse_response(r, HISTORY_SCHEMA) -async def times(connection, pubkey, start, end): +async def times(client: Client, pubkey: str, start: int, end: int) -> dict: """ GET public key transactions history between start and end timestamp - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str pubkey: Public key - :param int start: Start from timestamp - :param int end: End to timestamp + :param client: Client to connect to the api + :param pubkey: Public key + :param start: Start from timestamp + :param end: End to timestamp :return: dict """ - client = API(connection, URL_PATH) - - r = await client.requests_get('/history/%s/times/%s/%s' % (pubkey, start, end)) - return await parse_response(r, HISTORY_SCHEMA) + return await client.get(MODULE + '/history/%s/times/%s/%s' % (pubkey, start, end), schema=HISTORY_SCHEMA) diff --git a/duniterpy/api/bma/ud.py b/duniterpy/api/bma/ud.py index 33e94a50e7b7a0d4dd44f58a1bcba293fb858cf8..1a97ea35b26c5634e246b4a695a49b265e0fc9de 100644 --- a/duniterpy/api/bma/ud.py +++ b/duniterpy/api/bma/ud.py @@ -14,13 +14,13 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -# - -from duniterpy.api.bma import logging, API, parse_response +# vit +import logging +from duniterpy.api.client import Client logger = logging.getLogger("duniter/ud") -URL_PATH = 'ud' +MODULE = 'ud' UD_SCHEMA = { "type": "object", @@ -64,16 +64,14 @@ UD_SCHEMA = { "required": ["currency", "pubkey", "history"] } -async def history(connection, pubkey): + +async def history(client: Client, pubkey: str) -> dict: """ Get UD history of a member account - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str pubkey: Public key of the member - + :param client: Client to connect to the api + :param pubkey: Public key of the member :rtype: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/history/%s' % pubkey, schema=UD_SCHEMA) - r = await client.requests_get('/history/%s' % pubkey) - return await parse_response(r, UD_SCHEMA) diff --git a/duniterpy/api/bma/wot.py b/duniterpy/api/bma/wot.py index 45d5c86ac9ac07634bcdd2d72b7e152f67e4d20e..4b655d54761ac8cfb17c4b014cafa77b61a1bb80 100644 --- a/duniterpy/api/bma/wot.py +++ b/duniterpy/api/bma/wot.py @@ -14,13 +14,13 @@ # # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr -# -from duniterpy.api.bma import API, logging, parse_response +# vit +import logging +from duniterpy.api.client import Client logger = logging.getLogger("duniter/wot") -URL_PATH = 'wot' - +MODULE = 'wot' CERTIFICATIONS_SCHEMA = { "type": "object", @@ -297,109 +297,98 @@ LOOKUP_SCHEMA = { "required": ["partial", "results"] } -async def add(connection, identity): - """ - POST identity document - - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param duniterpy.documents.certification.Identity identity: Identity document - :rtype: aiohttp.ClientResponse - """ - client = API(connection, URL_PATH) - - r = await client.requests_post('/add', identity=identity) - return r -async def certify(connection, cert): - """ - POST certification document - - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param duniterpy.documents.certification.Certification cert: Certification document - :rtype: aiohttp.ClientResponse - """ - client = API(connection, URL_PATH) +# async def add(client: Client, identity: str) -> dict: +# """ +# POST identity document +# +# :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance +# :param duniterpy.documents.certification.Identity identity: Identity document +# :rtype: aiohttp.ClientResponse +# """ +# client = API(connection, URL_PATH) +# +# r = await client.requests_post('/add', identity=identity) +# return r - r = await client.requests_post('/certify', cert=cert) - return r -async def revoke(connection, revocation): - """ - POST revocation document +# async def certify(connection, cert): +# """ +# POST certification document +# +# :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance +# :param duniterpy.documents.certification.Certification cert: Certification document +# :rtype: aiohttp.ClientResponse +# """ +# client = API(connection, URL_PATH) +# +# r = await client.requests_post('/certify', cert=cert) +# return r - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param duniterpy.documents.certification.Revocation revocation: Certification document - :rtype: aiohttp.ClientResponse - """ - client = API(connection, URL_PATH) - r = await client.requests_post('/revoke', revocation=revocation) - return r +# async def revoke(connection, revocation): +# """ +# POST revocation document +# +# :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance +# :param duniterpy.documents.certification.Revocation revocation: Certification document +# :rtype: aiohttp.ClientResponse +# """ +# client = API(connection, URL_PATH) +# +# r = await client.requests_post('/revoke', revocation=revocation) +# return r -async def lookup(connection, search): +async def lookup(client: Client, search: str) -> dict: """ GET UID/Public key data - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str search: UID or public key + :param client: Client to connect to the api + :param search: UID or public key :rtype: dict """ - client = API(connection, URL_PATH) - - r = await client.requests_get('/lookup/%s' % search) - return await parse_response(r, LOOKUP_SCHEMA) + return await client.get(MODULE + '/lookup/%s' % search, schema=LOOKUP_SCHEMA) -async def certifiers_of(connection, search): +async def certifiers_of(client: Client, search: str) -> dict: """ GET UID/Public key certifiers - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str search: UID or public key + :param client: Client to connect to the api + :param search: UID or public key :rtype: dict """ + return await client.get(MODULE + '/certifiers-of/%s' % search, schema=CERTIFICATIONS_SCHEMA) - client = API(connection, URL_PATH) - - r = await client.requests_get('/certifiers-of/%s' % search) - return await parse_response(r, CERTIFICATIONS_SCHEMA) -async def certified_by(connection, search): +async def certified_by(client: Client, search: str) -> dict: """ GET identities certified by UID/Public key - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str search: UID or public key + :param client: Client to connect to the api + :param search: UID or public key :rtype: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/certified-by/%s' % search, schema=CERTIFICATIONS_SCHEMA) - r = await client.requests_get('/certified-by/%s' % search) - return await parse_response(r, CERTIFICATIONS_SCHEMA) -async def members(connection): +async def members(client: Client) -> dict: """ GET list of all current members of the Web of Trust - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :param client: Client to connect to the api :rtype: dict """ - client = API(connection, URL_PATH) + return await client.get(MODULE + '/members', schema=MEMBERS_SCHEMA) - r = await client.requests_get('/members') - return await parse_response(r, MEMBERS_SCHEMA) - -async def requirements(connection, search): +async def requirements(client: Client, search: str) -> dict: """ GET list of requirements for a given UID/Public key - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :param str search: UID or public key + :param client: Client to connect to the api + :param search: UID or public key :rtype: dict """ - client = API(connection, URL_PATH) - - r = await client.requests_get('/requirements/%s' % search) - return await parse_response(r, REQUIREMENTS_SCHEMA) + return await client.get(MODULE + '/requirements/%s' % search, schema=REQUIREMENTS_SCHEMA) diff --git a/duniterpy/api/bma/ws.py b/duniterpy/api/bma/ws.py index 6e36fddd19e5af4cce81c04962a400253c20c55e..ecd857f08070e48a642e2685d85ecbd8803d84a0 100644 --- a/duniterpy/api/bma/ws.py +++ b/duniterpy/api/bma/ws.py @@ -15,16 +15,17 @@ # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr # - -from duniterpy.api.bma import API, logging +# vit +import logging +from duniterpy.api.client import Client from duniterpy.api.bma.blockchain import BLOCK_SCHEMA logger = logging.getLogger("duniter/ws") -URL_PATH = 'ws' +MODULE = 'ws' +WS_BLOCK_SCHEMA = BLOCK_SCHEMA -WS_BLOCk_SCHEMA = BLOCK_SCHEMA WS_PEER_SCHEMA = { "type": "object", "properties": { @@ -51,23 +52,23 @@ WS_PEER_SCHEMA = { } -def block(connection): - """ - Connect to block websocket - - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :rtype: aiohttp.ClientWebSocketResponse - """ - client = API(connection, URL_PATH) - return client.connect_ws('/block') - +# def block(client: Client): +# """ +# Connect to block websocket +# +# :param client: Client to connect to the api +# :rtype: aiohttp.ClientWebSocketResponse +# """ +# client = API(connection, MODULE) +# return client.connect_ws('/block') -def peer(connection): - """ - Connect to peer websocket - :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance - :rtype: aiohttp.ClientWebSocketResponse - """ - client = API(connection, URL_PATH) - return client.connect_ws('/peer') +# def peer(client: Client): +# """ +# Connect to peer websocket +# +# :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance +# :rtype: aiohttp.ClientWebSocketResponse +# """ +# client = API(connection, MODULE) +# return client.connect_ws('/peer') diff --git a/duniterpy/api/bma/api.py b/duniterpy/api/client.py similarity index 71% rename from duniterpy/api/bma/api.py rename to duniterpy/api/client.py index 29fd926d43fb4b29d4ee2d1b6a692c502b5e50f8..1599fbfeb0c23393615c52fb7ece21d62694e567 100644 --- a/duniterpy/api/bma/api.py +++ b/duniterpy/api/client.py @@ -1,28 +1,13 @@ -# -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# # Authors: # Caner Candan <caner@candan.fr>, http://caner.candan.fr # Inso <insomniak.fr at gmail.com> - -import aiohttp import json import logging +import aiohttp import jsonschema -from ..errors import DuniterError +from .errors import DuniterError +from duniterpy.api.endpoint import endpoint logger = logging.getLogger("duniter") @@ -40,34 +25,12 @@ ERROR_SCHEMA = { } -class ConnectionHandler(object): - """Helper class used by other API classes to ease passing server connection information.""" - - def __init__(self, http_scheme, ws_scheme, server, port, path="", proxy=None, session=None): - """ - Init instance of connection handler - - :param str server: Server IP or domaine name - :param int port: Port - :param aiohttp.ClientSession|None session: Session AIOHTTP - """ - self.http_scheme = http_scheme - self.ws_scheme = ws_scheme - self.server = server - self.proxy = proxy - self.port = port - self.session = session - self.path = path - - def __str__(self): - return 'connection info: %s:%d' % (self.server, self.port) - - def parse_text(text, schema): """ Validate and parse the BMA answer from websocket :param str text: the bma answer + :param dict schema: dict for jsonschema :return: the json data """ try: @@ -112,7 +75,8 @@ async def parse_response(response, schema): class API(object): - """APIRequest is a class used as an interface. The intermediate derivated classes are the modules and the leaf classes are the API requests.""" + """APIRequest is a class used as an interface. The intermediate derivated classes are the modules and the leaf + classes are the API requests. """ schema = {} @@ -139,15 +103,15 @@ class API(object): server, port = self.connection_handler.server, self.connection_handler.port if self.connection_handler.path: url = '{scheme}://{server}:{port}/{path}/{module}'.format(scheme=scheme, - server=server, - port=port, - path=path, - module=self.module) + server=server, + port=port, + path=path, + module=self.module) else: url = '{scheme}://{server}:{port}/{module}'.format(scheme=scheme, - server=server, - port=port, - module=self.module) + server=server, + port=port, + module=self.module) return url + path @@ -201,3 +165,57 @@ class API(object): """ url = self.reverse_url(self.connection_handler.ws_scheme, path) return self.connection_handler.session.ws_connect(url, proxy=self.connection_handler.proxy) + + +class Client: + """ + Main class to create an API client + """ + def __init__(self, _endpoint: str, session: aiohttp.ClientSession = None, proxy: str = None): + """ + Init Client instance + + :param _endpoint: Endpoint string in duniter format + :param session: Aiohttp client session (optional, default None) + :param proxy: Proxy server as hostname:port + """ + # Endpoint Protocol detection + self.endpoint = endpoint(_endpoint) + + # if no user session... + if session is None: + # open a session + self.session = aiohttp.ClientSession() + else: + self.session = session + self.proxy = proxy + + async def get(self, url_path: str, params: dict = None, schema: dict = None)-> any: + """ + Get request on self.endpoint + url_path + + :param url_path: Url encoded path following the endpoint + :param params: Url query string parameters dictionary + :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), '') + + response = await client.requests_get(url_path, **params) + + if schema is not None: + return await parse_response(response, schema) + else: + return await response.json() + + async def close(self): + """ + Close aiohttp session + + :return: + """ + await self.session.close() + diff --git a/duniterpy/api/constants.py b/duniterpy/api/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..4ca0a4d93be336a1f7451b9addc84e07a2c311d4 --- /dev/null +++ b/duniterpy/api/constants.py @@ -0,0 +1,20 @@ + +uid_regex = "[A-Za-z0-9_-]{2,100}" +pubkey_regex = "(?![OIl])[1-9A-Za-z]{42,45}" +signature_regex = "[A-Za-z0-9+/]+(?:=|==)?" +block_hash_regex = "[0-9a-fA-F]{5,64}" +transaction_hash_regex = "[0-9a-fA-F]{5,64}" +hash_regex = "[A-F0-9]{64}" +block_id_regex = "[0-9]+" +block_uid_regex = "{block_id_regex}-{block_hash_regex}".format(block_id_regex=block_id_regex, + block_hash_regex=block_hash_regex) +conditions_regex = "(&&|\|\|| |[()]|(SIG\({pubkey_regex}\)|(XHX\({hash_regex}\))))*"\ + .format(pubkey_regex=pubkey_regex, hash_regex=hash_regex) +ipv4_regex = '(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' +ipv6_regex = '(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){,6}[0-9A-Fa-f]{1,4})?::)(?:%.+)?' +ws2pid_regex = "[0-9a-f]{8}" +host_regex = "[a-z0-9-_.]*(?:.[a-zA-Z])?" +path_regex = "[/\w \.-]*/?" +ws2p_private_prefix_regex = "O[CT][SAM]" +ws2p_public_prefix_regex = "I[CT]" +ws2p_head_regex = "HEAD:?(?:[0-9]+)?" diff --git a/duniterpy/api/elasticsearch/__init__.py b/duniterpy/api/elasticsearch/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/duniterpy/api/endpoint.py b/duniterpy/api/endpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..e4c4f7963328cb891494077b3c54e8716e30522e --- /dev/null +++ b/duniterpy/api/endpoint.py @@ -0,0 +1,427 @@ +import re +import aiohttp +from .constants import * +from ..documents import MalformedDocumentError + + +class ConnectionHandler: + """Helper class used by other API classes to ease passing server connection information.""" + + def __init__(self, http_scheme: str, ws_scheme: str, server: str, port: int, path: str = "", proxy: str = None, session: aiohttp.ClientSession = None): + """ + Init instance of connection handler + + :param http_scheme: Http scheme + :param ws_scheme: Web socket scheme + :param server: Server IP or domain name + :param port: Port number + :param port: Url path (optional, default="") + :param proxy: Proxy (optional, default=None) + :param session: Session AIOHTTP (optional, default=None) + """ + self.http_scheme = http_scheme + self.ws_scheme = ws_scheme + self.server = server + self.port = port + self.path = path + self.proxy = proxy + self.session = session + + def __str__(self)-> str: + return 'connection info: %s:%d' % (self.server, self.port) + + +class Endpoint: + @classmethod + def from_inline(cls, inline: str): + raise NotImplementedError("from_inline(..) is not implemented") + + def inline(self) -> str: + raise NotImplementedError("inline() is not implemented") + + def __str__(self) -> str: + raise NotImplementedError("__str__ is not implemented") + + def __eq__(self, other: any) -> bool: + raise NotImplementedError("__eq__ is not implemented") + + +class UnknownEndpoint(Endpoint): + API = None + + def __init__(self, api: str, properties: list): + self.api = api + self.properties = properties + + @classmethod + def from_inline(cls, inline: str): + """ + Return UnknownEndpoint instance from endpoint string + + :param inline: Endpoint string + :return: + """ + try: + api = inline.split()[0] + properties = inline.split()[1:] + return cls(api, properties) + except IndexError: + raise MalformedDocumentError(inline) + + def inline(self) -> str: + """ + Return endpoint string + + :return: + """ + doc = self.api + for p in self.properties: + doc += " {0}".format(p) + return doc + + def __str__(self) -> str: + return "{0} {1}".format(self.api, ' '.join(["{0}".format(p) for p in self.properties])) + + def __eq__(self, other: any) -> bool: + if isinstance(other, UnknownEndpoint): + return self.api == other.api and self.properties == other.properties + else: + return False + + def __hash__(self) -> int: + return hash((self.api, self.properties)) + + +ERROR_SCHEMA = { + "type": "object", + "properties": { + "ucode": { + "type": "number" + }, + "message": { + "type": "string" + } + }, + "required": ["ucode", "message"] +} + + +class BMAEndpoint(Endpoint): + API = "BASIC_MERKLED_API" + re_inline = re.compile( + '^BASIC_MERKLED_API(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))?(?: ([0-9]+))$'.format( + host_regex=host_regex, + ipv4_regex=ipv4_regex, + ipv6_regex=ipv6_regex)) + + def __init__(self, server: str, ipv4: str, ipv6: str, port: int): + """ + Init BMAEndpoint instance + + :param server: IP or domain name + :param ipv4: IP as IPv4 format + :param ipv6: IP as IPv6 format + :param port: Port number + """ + self.server = server + self.ipv4 = ipv4 + self.ipv6 = ipv6 + self.port = port + + @classmethod + def from_inline(cls, inline: str): + """ + Return BMAEndpoint instance from endpoint string + + :param inline: + :return: + """ + m = BMAEndpoint.re_inline.match(inline) + if m is None: + raise MalformedDocumentError(BMAEndpoint.API) + server = m.group(1) + ipv4 = m.group(2) + ipv6 = m.group(3) + port = int(m.group(4)) + return cls(server, ipv4, ipv6, port) + + def inline(self) -> str: + """ + Return endpoint string + + :return: + """ + return BMAEndpoint.API + "{DNS}{IPv4}{IPv6}{PORT}" \ + .format(DNS=(" {0}".format(self.server) if self.server else ""), + IPv4=(" {0}".format(self.ipv4) if self.ipv4 else ""), + IPv6=(" {0}".format(self.ipv6) if self.ipv6 else ""), + PORT=(" {0}".format(self.port) if self.port else "")) + + # fixme: session must be mandatory + def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: + """ + Return connection handler instance for the endpoint + + :param session: AIOHTTP client session instance + :param proxy: Proxy url + :return: + """ + if self.server: + return ConnectionHandler("http", "ws", self.server, self.port, "", proxy, session) + elif self.ipv6: + return ConnectionHandler("http", "ws", "[{0}]".format(self.ipv6), self.port, "", proxy, session) + + return ConnectionHandler("http", "ws", self.ipv4, self.port, "", proxy, session) + + def __str__(self): + return self.inline() + + def __eq__(self, other): + if isinstance(other, BMAEndpoint): + return self.server == other.server and self.ipv4 == other.ipv4 \ + and self.ipv6 == other.ipv6 and self.port == other.port + else: + return False + + def __hash__(self): + return hash((self.server, self.ipv4, self.ipv6, self.port)) + + +class SecuredBMAEndpoint(BMAEndpoint): + API = "BMAS" + re_inline = re.compile( + '^BMAS(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))? ([0-9]+)(?: ({path_regex}))?$'.format( + host_regex=host_regex, + ipv4_regex=ipv4_regex, + ipv6_regex=ipv6_regex, + path_regex=path_regex)) + + def __init__(self, server: str, ipv4: str, ipv6: str, port: int, path: str): + """ + Init SecuredBMAEndpoint instance + + :param server: IP or domain name + :param ipv4: IP as IPv4 format + :param ipv6: IP as IPv6 format + :param port: Port number + :param path: Url path + """ + super().__init__(server, ipv4, ipv6, port) + self.path = path + + @classmethod + def from_inline(cls, inline: str): + """ + Return SecuredBMAEndpoint instance from endpoint string + + :param inline: + :return: + """ + m = SecuredBMAEndpoint.re_inline.match(inline) + if m is None: + raise MalformedDocumentError(SecuredBMAEndpoint.API) + server = m.group(1) + ipv4 = m.group(2) + ipv6 = m.group(3) + port = int(m.group(4)) + path = m.group(5) + if not path: + path = "" + return cls(server, ipv4, ipv6, port, path) + + def inline(self) -> str: + """ + Return endpoint string + + :return: + """ + inlined = [str(info) for info in (self.server, self.ipv4, self.ipv6, self.port, self.path) if info] + return SecuredBMAEndpoint.API + " " + " ".join(inlined) + + # fixme: session must be mandatory + def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: + """ + Return connection handler instance for the endpoint + + :param session: AIOHTTP client session instance + :param proxy: Proxy url + :return: + """ + if self.server: + return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session) + elif self.ipv6: + return ConnectionHandler("https", "wss", "[{0}]".format(self.ipv6), self.port, self.path, proxy, session) + + return ConnectionHandler("https", "wss", self.ipv4, self.port, self.path, proxy, session) + + +class WS2PEndpoint(Endpoint): + API = "WS2P" + re_inline = re.compile( + '^WS2P ({ws2pid_regex}) ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)?(?: ({path_regex}))?$'.format( + ws2pid_regex=ws2pid_regex, + host_regex=host_regex, + ipv4_regex=ipv4_regex, + ipv6_regex=ipv6_regex, + path_regex=path_regex)) + + def __init__(self, ws2pid, server, port, path): + self.ws2pid = ws2pid + self.server = server + self.port = port + self.path = path + + @classmethod + def from_inline(cls, inline): + m = WS2PEndpoint.re_inline.match(inline) + if m is None: + raise MalformedDocumentError(WS2PEndpoint.API) + ws2pid = m.group(1) + server = m.group(2) + port = int(m.group(3)) + path = m.group(4) + if not path: + path = "" + return cls(ws2pid, server, port, path) + + def inline(self): + inlined = [str(info) for info in (self.ws2pid, self.server, self.port, self.path) if info] + return WS2PEndpoint.API + " " + " ".join(inlined) + + def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: + """ + Return connection handler instance for the endpoint + + :param aiohttp.ClientSession session: AIOHTTP client session instance + :param str proxy: Proxy url + :rtype: ConnectionHandler + """ + return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session) + + def __str__(self): + return self.inline() + + def __eq__(self, other): + if isinstance(other, WS2PEndpoint): + return self.server == other.server and self.ws2pid == other.ws2pid \ + and self.port == other.port and self.path == other.path + else: + return False + + def __hash__(self): + return hash((self.ws2pid, self.server, self.port, self.path)) + + +class ESUserEndpoint(Endpoint): + API = "ES_USER_API" + re_inline = re.compile( + '^ES_USER_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex, + host_regex=host_regex, + ipv4_regex=ipv4_regex)) + + def __init__(self, server, port): + self.server = server + self.port = port + + @classmethod + def from_inline(cls, inline): + m = ESUserEndpoint.re_inline.match(inline) + if m is None: + raise MalformedDocumentError(ESUserEndpoint.API) + server = m.group(1) + port = int(m.group(2)) + return cls(server, port) + + def inline(self): + inlined = [str(info) for info in (self.server, self.port) if info] + return ESUserEndpoint.API + " " + " ".join(inlined) + + def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: + """ + Return connection handler instance for the endpoint + + :param aiohttp.ClientSession session: AIOHTTP client session instance + :param str proxy: Proxy url + :rtype: ConnectionHandler + """ + return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session) + + def __str__(self): + return self.inline() + + def __eq__(self, other): + if isinstance(other, ESUserEndpoint): + return self.server == other.server and self.port == other.port + else: + return False + + def __hash__(self): + return hash((self.server, self.port)) + + +class ESSubscribtionEndpoint(Endpoint): + API = "ES_SUBSCRIPTION_API" + re_inline = re.compile( + '^ES_SUBSCRIPTION_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex, + host_regex=host_regex, + ipv4_regex=ipv4_regex)) + + def __init__(self, server, port): + self.server = server + self.port = port + + @classmethod + def from_inline(cls, inline): + m = ESSubscribtionEndpoint.re_inline.match(inline) + if m is None: + raise MalformedDocumentError(ESSubscribtionEndpoint.API) + server = m.group(1) + port = int(m.group(2)) + return cls(server, port) + + def inline(self): + inlined = [str(info) for info in (self.server, self.port) if info] + return ESSubscribtionEndpoint.API + " " + " ".join(inlined) + + def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: + """ + Return connection handler instance for the endpoint + + :param aiohttp.ClientSession session: AIOHTTP client session instance + :param str proxy: Proxy url + :rtype: ConnectionHandler + """ + return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session) + + def __str__(self): + return self.inline() + + def __eq__(self, other): + if isinstance(other, ESSubscribtionEndpoint): + return self.server == other.server and self.port == other.port + else: + return False + + def __hash__(self): + return hash((ESSubscribtionEndpoint.API, self.server, self.port)) + + +MANAGED_API = { + BMAEndpoint.API: BMAEndpoint, + SecuredBMAEndpoint.API: SecuredBMAEndpoint, + WS2PEndpoint.API: WS2PEndpoint, + ESUserEndpoint.API: ESUserEndpoint, + ESSubscribtionEndpoint.API: ESSubscribtionEndpoint +} + + +def endpoint(value): + if issubclass(type(value), Endpoint): + return value + elif isinstance(value, str): + for api, cls in MANAGED_API.items(): + if value.startswith(api + " "): + return cls.from_inline(value) + return UnknownEndpoint.from_inline(value) + else: + raise TypeError("Cannot convert {0} to endpoint".format(value)) diff --git a/duniterpy/api/ws2p/__init__.py b/duniterpy/api/ws2p/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/duniterpy/api/ws2p/network.py b/duniterpy/api/ws2p/network.py new file mode 100644 index 0000000000000000000000000000000000000000..14b331c53ced6cd584bd7f873f7502ad6c9c89d1 --- /dev/null +++ b/duniterpy/api/ws2p/network.py @@ -0,0 +1,68 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from duniterpy.api.client import API, logging, parse_response + +logger = logging.getLogger("duniter/network") + +URL_PATH = 'network' + +WS2P_HEADS_SCHEMA = { + "type": "object", + "properties": { + "heads": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "sig": { + "type": "string", + }, + "messageV2": { + "type": "string" + }, + "sigV2": { + "type": "string", + }, + "step": { + "type": "number", + }, + }, + "required": ["message", "sig"] + } + } + }, + "required": ["heads"] + } + + +async def heads(connection): + """ + GET Certification data over a member + + :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance + :rtype: dict + """ + + client = API(connection, URL_PATH) + + r = await client.requests_get('/ws2p/heads') + return await parse_response(r, WS2P_HEADS_SCHEMA) diff --git a/duniterpy/documents/__init__.py b/duniterpy/documents/__init__.py index e313598de4c22196820c19d6e82f7dcc0a120338..29f7818a822fd811521c7ec63ccb9e041d42858c 100644 --- a/duniterpy/documents/__init__.py +++ b/duniterpy/documents/__init__.py @@ -1,7 +1,6 @@ from .block import Block, BlockUID, block_uid from .certification import Identity, Certification, Revocation from .membership import Membership -from .peer import endpoint, BMAEndpoint, UnknownEndpoint, Peer, SecuredBMAEndpoint, WS2PEndpoint from .transaction import SimpleTransaction, Transaction, InputSource, OutputSource, \ SIGParameter, Unlock, UnlockParameter from .document import Document, MalformedDocumentError diff --git a/duniterpy/documents/peer.py b/duniterpy/documents/peer.py index a638d53655f6fd6df78a0697fcafff3c9f8e4dbf..60255e123109de1c9862d999896be8c3d6fea017 100644 --- a/duniterpy/documents/peer.py +++ b/duniterpy/documents/peer.py @@ -1,11 +1,9 @@ import re -import aiohttp -from typing import Generator -from ..api.bma import ConnectionHandler -from .document import Document, MalformedDocumentError +from duniterpy.api.endpoint import endpoint +from .document import Document from . import BlockUID -from .constants import block_hash_regex, pubkey_regex, ipv4_regex, ipv6_regex, ws2pid_regex, host_regex, path_regex +from .constants import block_hash_regex, pubkey_regex class Peer(Document): @@ -37,12 +35,12 @@ class Peer(Document): "Endpoints": re_endpoints }} - def __init__(self, version, currency, pubkey, blockUID, + def __init__(self, version, currency, pubkey, block_uid, endpoints, signature): super().__init__(version, currency, [signature]) self.pubkey = pubkey - self.blockUID = blockUID + self.blockUID = block_uid self.endpoints = endpoints @classmethod @@ -62,7 +60,7 @@ class Peer(Document): pubkey = Peer.parse_field("Pubkey", lines[n]) n += 1 - blockUID = BlockUID.from_str(Peer.parse_field("Block", lines[n])) + block_uid = BlockUID.from_str(Peer.parse_field("Block", lines[n])) n += 1 Peer.parse_field("Endpoints", lines[n]) @@ -75,7 +73,7 @@ class Peer(Document): signature = Peer.re_signature.match(lines[n]).group(1) - return cls(version, currency, pubkey, blockUID, endpoints, signature) + return cls(version, currency, pubkey, block_uid, endpoints, signature) def raw(self): doc = """Version: {0} @@ -86,330 +84,7 @@ Block: {3} Endpoints: """.format(self.version, self.currency, self.pubkey, self.blockUID) - for endpoint in self.endpoints: - doc += "{0}\n".format(endpoint.inline()) + for _endpoint in self.endpoints: + doc += "{0}\n".format(_endpoint.inline()) return doc - - -def endpoint(value): - if issubclass(type(value), Endpoint): - return value - elif isinstance(value, str): - for api, cls in MANAGED_API.items(): - if value.startswith(api + " "): - return cls.from_inline(value) - return UnknownEndpoint.from_inline(value) - else: - raise TypeError("Cannot convert {0} to endpoint".format(value)) - - -class Endpoint(): - @classmethod - def from_inline(cls, inline): - raise NotImplementedError("from_inline(..) is not implemented") - - def inline(self): - raise NotImplementedError("inline() is not implemented") - - def __str__(self): - raise NotImplementedError("__str__ is not implemented") - - def __eq__(self, other): - raise NotImplementedError("__eq__ is not implemented") - - -class UnknownEndpoint(Endpoint): - API = None - - def __init__(self, api, properties): - self.api = api - self.properties = properties - - @classmethod - def from_inline(cls, inline): - try: - api = inline.split()[0] - properties = inline.split()[1:] - return cls(api, properties) - except IndexError: - raise MalformedDocumentError(inline) - - def inline(self): - doc = self.api - for p in self.properties: - doc += " {0}".format(p) - return doc - - def __str__(self): - return "{0} {1}".format(self.api, ' '.join(["{0}".format(p) for p in self.properties])) - - def __eq__(self, other): - if isinstance(other, UnknownEndpoint): - return self.api == other.api and self.properties == other.properties - else: - return False - - def __hash__(self): - return hash((self.api, self.properties)) - - -class BMAEndpoint(Endpoint): - API = "BASIC_MERKLED_API" - re_inline = re.compile('^BASIC_MERKLED_API(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))?(?: ([0-9]+))$'.format(host_regex=host_regex, - ipv4_regex=ipv4_regex, - ipv6_regex=ipv6_regex)) - - def __init__(self, server, ipv4, ipv6, port): - self.server = server - self.ipv4 = ipv4 - self.ipv6 = ipv6 - self.port = port - - @classmethod - def from_inline(cls, inline): - m = BMAEndpoint.re_inline.match(inline) - str_re = BMAEndpoint.re_inline.pattern - if m is None: - raise MalformedDocumentError(BMAEndpoint.API) - server = m.group(1) - ipv4 = m.group(2) - ipv6 = m.group(3) - port = int(m.group(4)) - return cls(server, ipv4, ipv6, port) - - def inline(self): - return BMAEndpoint.API + "{DNS}{IPv4}{IPv6}{PORT}" \ - .format(DNS=(" {0}".format(self.server) if self.server else ""), - IPv4=(" {0}".format(self.ipv4) if self.ipv4 else ""), - IPv6=(" {0}".format(self.ipv6) if self.ipv6 else ""), - PORT=(" {0}".format(self.port) if self.port else "")) - - def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: - """ - Return connection handler instance for the endpoint - - :param aiohttp.ClientSession session: AIOHTTP client session instance - :param str proxy: Proxy url - :rtype: ConnectionHandler - """ - if self.server: - return ConnectionHandler("http", "ws", self.server, self.port, "", proxy, session) - elif self.ipv6: - return ConnectionHandler("http", "ws", "[{0}]".format(self.ipv6), self.port, "", proxy, session) - - return ConnectionHandler("http", "ws", self.ipv4, self.port, "", proxy, session) - - def __str__(self): - return self.inline() - - def __eq__(self, other): - if isinstance(other, BMAEndpoint): - return self.server == other.server and self.ipv4 == other.ipv4 \ - and self.ipv6 == other.ipv6 and self.port == other.port - else: - return False - - def __hash__(self): - return hash((self.server, self.ipv4, self.ipv6, self.port)) - - -class SecuredBMAEndpoint(BMAEndpoint): - API = "BMAS" - re_inline = re.compile('^BMAS(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))? ([0-9]+)(?: ({path_regex}))?$'.format(host_regex=host_regex, - ipv4_regex=ipv4_regex, - ipv6_regex=ipv6_regex, - path_regex=path_regex)) - - def __init__(self, server, ipv4, ipv6, port, path): - super().__init__(server, ipv4, ipv6, port) - self.path = path - - @classmethod - def from_inline(cls, inline): - m = SecuredBMAEndpoint.re_inline.match(inline) - if m is None: - raise MalformedDocumentError(SecuredBMAEndpoint.API) - server = m.group(1) - ipv4 = m.group(2) - ipv6 = m.group(3) - port = int(m.group(4)) - path = m.group(5) - if not path: - path = "" - return cls(server, ipv4, ipv6, port, path) - - def inline(self): - inlined = [str(info) for info in (self.server, self.ipv4, self.ipv6, self.port, self.path) if info] - return SecuredBMAEndpoint.API + " " + " ".join(inlined) - - def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: - """ - Return connection handler instance for the endpoint - - :param aiohttp.ClientSession session: AIOHTTP client session instance - :param str proxy: Proxy url - :rtype: ConnectionHandler - """ - if self.server: - return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session) - elif self.ipv6: - return ConnectionHandler("https", "wss", "[{0}]".format(self.ipv6), self.port, self.path, proxy, session) - - return ConnectionHandler("https", "wss", self.ipv4, self.port, self.path, proxy, session) - - -class WS2PEndpoint(Endpoint): - API = "WS2P" - re_inline = re.compile('^WS2P ({ws2pid_regex}) ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)?(?: ({path_regex}))?$'.format(ws2pid_regex=ws2pid_regex, - host_regex=host_regex, - ipv4_regex=ipv4_regex, - ipv6_regex=ipv6_regex, - path_regex=path_regex)) - - def __init__(self, ws2pid, server, port, path): - self.ws2pid = ws2pid - self.server = server - self.port = port - self.path = path - - @classmethod - def from_inline(cls, inline): - m = WS2PEndpoint.re_inline.match(inline) - if m is None: - raise MalformedDocumentError(WS2PEndpoint.API) - ws2pid = m.group(1) - server = m.group(2) - port = int(m.group(3)) - path = m.group(4) - if not path: - path = "" - return cls(ws2pid, server, port, path) - - def inline(self): - inlined = [str(info) for info in (self.ws2pid, self.server, self.port, self.path) if info] - return WS2PEndpoint.API + " " + " ".join(inlined) - - def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: - """ - Return connection handler instance for the endpoint - - :param aiohttp.ClientSession session: AIOHTTP client session instance - :param str proxy: Proxy url - :rtype: ConnectionHandler - """ - return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session) - - def __str__(self): - return self.inline() - - def __eq__(self, other): - if isinstance(other, WS2PEndpoint): - return self.server == other.server and self.ws2pid == other.ws2pid \ - and self.port == other.port and self.path == other.path - else: - return False - - def __hash__(self): - return hash((self.ws2pid, self.server, self.port, self.path)) - - -class ESUserEndpoint(Endpoint): - API = "ES_USER_API" - re_inline = re.compile('^ES_USER_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex, - host_regex=host_regex, - ipv4_regex=ipv4_regex)) - - def __init__(self, server, port): - self.server = server - self.port = port - - @classmethod - def from_inline(cls, inline): - m = ESUserEndpoint.re_inline.match(inline) - if m is None: - raise MalformedDocumentError(ESUserEndpoint.API) - server = m.group(1) - port = int(m.group(2)) - return cls(server, port) - - def inline(self): - inlined = [str(info) for info in (self.server, self.port) if info] - return ESUserEndpoint.API + " " + " ".join(inlined) - - def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: - """ - Return connection handler instance for the endpoint - - :param aiohttp.ClientSession session: AIOHTTP client session instance - :param str proxy: Proxy url - :rtype: ConnectionHandler - """ - return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session) - - def __str__(self): - return self.inline() - - def __eq__(self, other): - if isinstance(other, ESUserEndpoint): - return self.server == other.server and self.port == other.port - else: - return False - - def __hash__(self): - return hash((self.server, self.port)) - - -class ESSubscribtionEndpoint(Endpoint): - API = "ES_SUBSCRIPTION_API" - re_inline = re.compile('^ES_SUBSCRIPTION_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex, - host_regex=host_regex, - ipv4_regex=ipv4_regex)) - - def __init__(self, server, port): - self.server = server - self.port = port - - @classmethod - def from_inline(cls, inline): - m = ESSubscribtionEndpoint.re_inline.match(inline) - if m is None: - raise MalformedDocumentError(ESSubscribtionEndpoint.API) - server = m.group(1) - port = int(m.group(2)) - return cls(server, port) - - def inline(self): - inlined = [str(info) for info in (self.server, self.port) if info] - return ESSubscribtionEndpoint.API + " " + " ".join(inlined) - - def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler: - """ - Return connection handler instance for the endpoint - - :param aiohttp.ClientSession session: AIOHTTP client session instance - :param str proxy: Proxy url - :rtype: ConnectionHandler - """ - return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session) - - def __str__(self): - return self.inline() - - def __eq__(self, other): - if isinstance(other, ESSubscribtionEndpoint): - return self.server == other.server and self.port == other.port - else: - return False - - def __hash__(self): - return hash((ESSubscribtionEndpoint.API, self.server, self.port)) - - -MANAGED_API = { - BMAEndpoint.API: BMAEndpoint, - SecuredBMAEndpoint.API: SecuredBMAEndpoint, - WS2PEndpoint.API: WS2PEndpoint, - ESUserEndpoint.API: ESUserEndpoint, - ESSubscribtionEndpoint.API: ESSubscribtionEndpoint -} diff --git a/examples/create_and_publish_identity.py b/examples/create_and_publish_identity.py index b4fb846d6cafff1293c07c70e1bd278cd034a44f..60ba1d92ae4694b2d84a32084c5eca701d355151 100644 --- a/examples/create_and_publish_identity.py +++ b/examples/create_and_publish_identity.py @@ -3,7 +3,8 @@ import aiohttp import getpass import duniterpy.api.bma as bma -from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity +from duniterpy.api.endpoint import SecuredBMAEndpoint +from duniterpy.documents import BlockUID, Identity from duniterpy.key import SigningKey @@ -12,7 +13,7 @@ from duniterpy.key import SigningKey # 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) -BMA_ENDPOINT = "BMAS g1-test.duniter.org 443" +BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" # Your unique identifier in the Web of Trust UID = "MyIdentityTest" @@ -63,7 +64,7 @@ async def main(): """ # connection handler from BMA endpoint - connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION) + connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION) # capture current block to get version and currency and blockstamp current_block = await bma.blockchain.current(connection) diff --git a/examples/request_data.py b/examples/request_data.py index 87efed5f6b2b0dd12d99758e45c9e2bc9503add0..baac93dbeb0ff7a3131b17c7be6b3cfa4971d020 100644 --- a/examples/request_data.py +++ b/examples/request_data.py @@ -1,47 +1,47 @@ import asyncio -import aiohttp -import duniterpy.api.bma as bma -from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint +from duniterpy.api.client import Client +from duniterpy.api import bma # 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) -BMA_ENDPOINT = "BMAS g1-test.duniter.org 443" +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() - async def main(): """ Main code """ - # connection handler from BMA endpoint - connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION) + # Create Client from endpoint string in Duniter format + client = Client(BMAS_ENDPOINT) + + # Get the node summary infos (direct REST GET request) + response = await client.get('node/summary') + print(response) - # Get the node summary infos - response = await bma.node.summary(connection) + # Get the node summary infos by dedicated method (with json schema validation) + response = await bma.node.summary(client) print(response) - # Get the current block data - response = await bma.blockchain.parameters(connection) + # Get the money parameters located in the first block + response = await bma.blockchain.parameters(client) print(response) - # Get the current block data - response = await bma.blockchain.current(connection) + # Get the current block + response = await bma.blockchain.current(client) print(response) # Get the block number 10 - response = await bma.blockchain.block(connection, 10) + response = await bma.blockchain.block(client, 10) print(response) -with AIOHTTP_SESSION: + # 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()) +# 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/save_revoke_document.py b/examples/save_revoke_document.py index 1209db35237b233c67a004222f358d6b0ed816de..ae08e4121c1f2950ef2c3bb03578de3ca861a8f9 100644 --- a/examples/save_revoke_document.py +++ b/examples/save_revoke_document.py @@ -1,8 +1,8 @@ import asyncio import aiohttp import duniterpy.api.bma as bma -from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity -from duniterpy.documents import Revocation +from duniterpy.api.endpoint import SecuredBMAEndpoint +from duniterpy.documents import Revocation, BlockUID, Identity from duniterpy.key import SigningKey import getpass import os @@ -21,7 +21,7 @@ else: # 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) -BMA_ENDPOINT = "BMAS g1-test.duniter.org 443" +BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" # WARNING : Hide this file in a safe and secure place # If one day you forget your credentials, @@ -39,7 +39,7 @@ async def get_identity_document(connection, currency, pubkey): """ Get the Identity document of the pubkey - :param bma.api.ConnectionHandler connection: Connection handler + :param bma.connection.ConnectionHandler connection: Connection handler :param str currency: Currency name :param str pubkey: Public key @@ -82,8 +82,8 @@ def get_revoke_document(identity, salt, password): :param str salt: Salt :param str password: Password - :return: the revokation document - :rtype: duniterpy.documents.certification.Revocation + :return: the raw signed revokation document + :rtype: str """ document = Revocation(PROTOCOL_VERSION, identity.currency, identity.pubkey, "") @@ -91,6 +91,7 @@ def get_revoke_document(identity, salt, password): document.sign(identity, [key]) return document.signed_raw(identity) + async def main(): """ Main code @@ -113,7 +114,7 @@ async def main(): exit(0) # connection handler from BMAS endpoint - connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION) + connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION) # capture current block to get currency name current_block = await bma.blockchain.current(connection) diff --git a/examples/send_certification.py b/examples/send_certification.py index d31fb76590e4790754c71049d6b2bef2eb5f0d1e..1391a18960e6b5cbfb4fbdb5e7f87724810566c2 100644 --- a/examples/send_certification.py +++ b/examples/send_certification.py @@ -2,7 +2,8 @@ import asyncio import aiohttp import getpass import duniterpy.api.bma as bma -from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity, Certification +from duniterpy.api.endpoint import SecuredBMAEndpoint +from duniterpy.documents import BlockUID, Identity, Certification from duniterpy.key import SigningKey @@ -11,7 +12,7 @@ from duniterpy.key import SigningKey # 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) -BMA_ENDPOINT = "BMAS g1-test.duniter.org 443" +BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" ################################################ @@ -24,7 +25,7 @@ async def get_identity_document(connection, current_block, pubkey): """ Get the identity document of the pubkey - :param bma.api.ConnectionHandler connection: Connection handler + :param bma.connection.ConnectionHandler connection: Connection handler :param dict current_block: Current block data :param str pubkey: UID/Public key @@ -92,7 +93,7 @@ async def main(): Main code """ # connection handler from BMA endpoint - connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION) + connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION) # prompt hidden user entry salt = getpass.getpass("Enter your passphrase (salt): ") diff --git a/examples/send_membership.py b/examples/send_membership.py index 790aa6a36ca6e7f8608d156626adbce0f01b83f7..7a85af848adafbf0679b291cc7dc7235cb96e203 100644 --- a/examples/send_membership.py +++ b/examples/send_membership.py @@ -3,7 +3,8 @@ import aiohttp import getpass import duniterpy.api.bma as bma -from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity, Membership +from duniterpy.api.endpoint import SecuredBMAEndpoint +from duniterpy.documents import BlockUID, Identity, Membership from duniterpy.key import SigningKey @@ -12,7 +13,7 @@ from duniterpy.key import SigningKey # 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) -BMA_ENDPOINT = "BMAS g1-test.duniter.org 443" +BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" ################################################ @@ -97,7 +98,7 @@ async def main(): Main code """ # connection handler from BMA endpoint - connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION) + connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION) # capture current block to get version and currency and blockstamp current_block = await bma.blockchain.current(connection) diff --git a/examples/send_transaction.py b/examples/send_transaction.py index efd75736cbc06bbb227e701ccf92a7068282f6bf..98b6d9fe86909a174149ef7b840a05449b304ded 100644 --- a/examples/send_transaction.py +++ b/examples/send_transaction.py @@ -3,7 +3,8 @@ import getpass import aiohttp from duniterpy.api import bma -from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Transaction +from duniterpy.api.endpoint import SecuredBMAEndpoint +from duniterpy.documents import BlockUID, Transaction from duniterpy.documents.transaction import InputSource, OutputSource, Unlock, SIGParameter from duniterpy.grammars.output import Condition, SIG from duniterpy.key import SigningKey @@ -13,7 +14,7 @@ from duniterpy.key import SigningKey # 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) -BMA_ENDPOINT = "BMAS g1-test.duniter.org 443" +BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443" ################################################ @@ -95,7 +96,7 @@ async def main(): Main code """ # connection handler from BMA endpoint - connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION) + connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION) # prompt hidden user entry salt = getpass.getpass("Enter your passphrase (salt): ") diff --git a/tests/api/bma/test_ws.py b/tests/api/bma/test_ws.py index a7fcfca779605bc9bc3310d9e63970465233ed80..511c3623eaa06000bf8c8bba94c69a79e973ac9c 100644 --- a/tests/api/bma/test_ws.py +++ b/tests/api/bma/test_ws.py @@ -1,6 +1,6 @@ import unittest from tests.api.webserver import WebFunctionalSetupMixin -from duniterpy.api.bma.ws import block, peer, WS_BLOCk_SCHEMA, WS_PEER_SCHEMA +from duniterpy.api.bma.ws import block, peer, WS_BLOCK_SCHEMA, WS_PEER_SCHEMA from duniterpy.api.bma import parse_text @@ -81,7 +81,7 @@ class Test_BMA_Websocket(WebFunctionalSetupMixin, unittest.TestCase): "signature": "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw==" } """ - parse_text(json_sample, WS_BLOCk_SCHEMA) + parse_text(json_sample, WS_BLOCK_SCHEMA) def test_peer(self): json_sample = """{