Skip to content
Snippets Groups Projects
Select Git revision
  • dev
  • 1291-write-contributing-workflow
  • feature/info-peers
  • feature/husky-linting
  • husky-linting-hooks
  • info-peer
  • up-dependencies
  • wizard-key-public
  • 1.7
  • fix/1394/4-certs-only
  • fix/1396/integ
  • test-ci
  • master
  • nodejs10_deprecations
  • feat/sodium
  • 1.6
  • issue_1282
  • build
  • sync
  • test_prebuilt_nm
  • v1.7.21
  • v1.7.20
  • v1.7.19
  • v1.7.18
  • v1.7.17
  • v1.6.32
  • v1.7.13
  • 2019.0407.1508
  • v1.7.16
  • 2019.0405.1251
  • 2019.0407.1406
  • v1.7.15
  • 2019.0403.1317
  • v1.7.14
  • 2019.0329.1732
  • 2019.0327.1837
  • 2019.0325.1919
  • 2019.0324.1706
  • ww-0.1
  • v1.7.12
40 results

README.md

Blame
  • Forked from nodes / typescript / duniter
    Source project has a limited visibility.
    request_ws2p.py 11.57 KiB
    import asyncio
    import json
    import time
    
    from _socket import gaierror
    
    import aiohttp
    import jsonschema
    from jsonschema import ValidationError
    
    from duniterpy.tools import get_ws2p_challenge
    from duniterpy.key import SigningKey
    
    from duniterpy.api import ws2p
    from duniterpy.api.ws2p import requests
    from duniterpy.documents.ws2p.messages import Connect, Ack, Ok
    from duniterpy.api.client import Client, parse_text
    
    # 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 WS2P API (WS2P)
    WS2P_ENDPOINT = "WS2P 2f731dcd 127.0.0.1 20900"
    CURRENCY = "g1-test"
    
    
    ################################################
    
    
    async def main():
        """
        Main code
        """
    
        # # Prompt hidden user entry
        # salt = getpass.getpass("Enter your passphrase (salt): ")
        #
        # # Prompt hidden user entry
        # password = getpass.getpass("Enter your password: ")
        salt = password = "toto"
    
        # Init signing_key instance
        signing_key = SigningKey.from_credentials(salt, password)
    
        connect_document = Connect(CURRENCY, signing_key.pubkey)
        connect_message = connect_document.get_signed_json(signing_key)
    
        # Create Client from endpoint string in Duniter format
        client = Client(WS2P_ENDPOINT)
    
        try:
            # Create Web Socket connection on block path
            ws_connection = client.connect_ws()
    
            # 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 web socket endpoint")
    
                # START HANDSHAKE #######################################################
                print("\nSTART HANDSHAKE...")
    
                print("Send CONNECT message")
                await ws.send_str(connect_message)
    
                # Iterate on each message received...
                async for msg in ws:  # type: aiohttp.WSMessage
    
                    # Display incoming message from peer
                    print(msg)
    
                    # If message type is text...
                    if msg.type == aiohttp.WSMsgType.TEXT:
                        # print(msg.data)
                        try:
                            # Validate json string with jsonschema and return a dict
                            data = parse_text(msg.data, ws2p.network.WS2P_CONNECT_MESSAGE_SCHEMA)
    
                        except jsonschema.exceptions.ValidationError:
                            try:
                                # Validate json string with jsonschema and return a dict
                                data = parse_text(msg.data, ws2p.network.WS2P_ACK_MESSAGE_SCHEMA)
    
                            except jsonschema.exceptions.ValidationError:
                                try:
                                    # Validate json string with jsonschema and return a dict
                                    data = parse_text(msg.data, ws2p.network.WS2P_OK_MESSAGE_SCHEMA)
    
                                except jsonschema.exceptions.ValidationError:
                                    continue
    
                                print("Received a OK message")
    
                                Ok(CURRENCY, remote_connect_document.pubkey, connect_document.challenge, data["sig"])
                                print("Received OK message signature is valid")
    
                                # END HANDSHAKE #######################################################
                                print("END OF HANDSHAKE\n")
    
                                # Uncomment the following command to stop listening for messages anymore
                                break
    
                                # Uncomment the following commands to continue to listen incoming messages
                                # print("waiting for incoming messages...\n")
                                # continue
    
                            print("Received a ACK message")
    
                            # Create ACK document from ACK response to verify signature
                            Ack(CURRENCY, data["pub"], connect_document.challenge, data["sig"])
                            print("Received ACK message signature is valid")
                            # If ACK response is ok, create OK message
                            ok_message = Ok(CURRENCY, signing_key.pubkey, connect_document.challenge).get_signed_json(
                                signing_key)
    
                            # Send OK message
                            print("Send OK message...")
                            await ws.send_str(ok_message)
                            continue
    
                        print("Received a CONNECT message")
    
                        remote_connect_document = Connect(CURRENCY, data["pub"], data["challenge"], data["sig"])
                        print("Received CONNECT message signature is valid")
    
                        ack_message = Ack(CURRENCY, signing_key.pubkey,
                                          remote_connect_document.challenge).get_signed_json(
                            signing_key)
                        # Send ACK message
                        print("Send ACK message...")
                        await ws.send_str(ack_message)
    
                    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 !")
    
                # Send ws2p request
                print("Send getCurrent() request")
                request_id = get_ws2p_challenge()[:8]
                await ws.send_str(requests.get_current(request_id))
    
                # Wait response with request id
                response_str = await ws.receive_str()
                while "resId" not in json.loads(response_str) or (
                        "resId" in json.loads(response_str) and json.loads(response_str)["resId"] != request_id):
                    response_str = await ws.receive_str()
                    time.sleep(1)
                try:
                    # Check response format
                    parse_text(response_str, requests.BLOCK_RESPONSE_SCHEMA)
                    # If valid display response
                    print("Response: " + response_str)
                except ValidationError:
                    # If invalid response...
                    try:
                        # Check error response format
                        parse_text(response_str, requests.ERROR_RESPONSE_SCHEMA)
                        # If valid, display error response
                        print("Error response: " + response_str)
                    except ValidationError as exception:
                        # If invalid, display exception on response validation
                        print(exception)
    
                # Send ws2p request
                print("Send getBlock(360000) request")
                request_id = get_ws2p_challenge()[:8]
                await ws.send_str(requests.get_block(request_id, 360000))
    
                # Wait response with request id
                response_str = await ws.receive_str()
                while "resId" not in json.loads(response_str) or (
                        "resId" in json.loads(response_str) and json.loads(response_str)["resId"] != request_id):
                    response_str = await ws.receive_str()
                    time.sleep(1)
                try:
                    # Check response format
                    parse_text(response_str, requests.BLOCK_RESPONSE_SCHEMA)
                    # If valid display response
                    print("Response: " + response_str)
                except ValidationError:
                    # If invalid response...
                    try:
                        # Check error response format
                        parse_text(response_str, requests.ERROR_RESPONSE_SCHEMA)
                        # If valid, display error response
                        print("Error response: " + response_str)
                    except ValidationError as exception:
                        # If invalid, display exception on response validation
                        print(exception)
    
                # Send ws2p request
                print("Send getBlocks(360000, 2) request")
                request_id = get_ws2p_challenge()[:8]
                await ws.send_str(requests.get_blocks(request_id, 360000, 2))
    
                # Wait response with request id
                response_str = await ws.receive_str()
                while "resId" not in json.loads(response_str) or (
                        "resId" in json.loads(response_str) and json.loads(response_str)["resId"] != request_id):
                    response_str = await ws.receive_str()
                    time.sleep(1)
                try:
                    # Check response format
                    parse_text(response_str, requests.BLOCKS_RESPONSE_SCHEMA)
                    # If valid display response
                    print("Response: " + response_str)
                except ValidationError:
                    # If invalid response...
                    try:
                        # Check error response format
                        parse_text(response_str, requests.ERROR_RESPONSE_SCHEMA)
                        # If valid, display error response
                        print("Error response: " + response_str)
                    except ValidationError as exception:
                        # If invalid, display exception on response validation
                        print(exception)
    
                # Send ws2p request
                print("Send getRequirementsPending(3) request")
                request_id = get_ws2p_challenge()[:8]
                await ws.send_str(requests.get_requirements_pending(request_id, 3))
                # Wait response with request id
                response_str = await ws.receive_str()
                while "resId" not in json.loads(response_str) or (
                        "resId" in json.loads(response_str) and json.loads(response_str)["resId"] != request_id):
                    response_str = await ws.receive_str()
                    time.sleep(1)
                try:
                    # Check response format
                    parse_text(response_str, requests.REQUIREMENTS_RESPONSE_SCHEMA)
                    # If valid display response
                    print("Response: " + response_str)
                except ValidationError:
                    # If invalid response...
                    try:
                        # Check error response format
                        parse_text(response_str, requests.ERROR_RESPONSE_SCHEMA)
                        # If valid, display error response
                        print("Error response: " + response_str)
                    except ValidationError as exception:
                        # If invalid, display exception on response validation
                        print(exception)
    
                # Close session
                await client.close()
    
        except (aiohttp.WSServerHandshakeError, ValueError) as e:
            print("Websocket handshake {0} : {1}".format(type(e).__name__, str(e)))
        except (aiohttp.ClientError, gaierror, TimeoutError) as e:
            print("{0} : {1}".format(str(e), WS2P_ENDPOINT))
        except jsonschema.ValidationError as e:
            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())