Metadata-Version: 2.1
Name: p2py
Version: 0.23
Summary: The simplest peer to peer networking Python library
Home-page: https://github.com/ipds/p2py
Author: Adam Szokalski
Author-email: aszokalski@ipds.team
License: AGPLv3
Download-URL: https://github.com/ipds/p2py/archive/0.1.tar.gz
Description: ## What is p2py
        
        It's a simple peer to peer networking library based on [Chord](http://nms.lcs.mit.edu/papers/chord.pdf) made for [IPDS project](https://github.com/ipds/IPDS-Python). 
        
        The goal of this project is to create a extraordinarly simple to use yet powerfull peer to peer networking library for Python. It's created for [IPDS project](https://github.com/ipds/IPDS-Python) but can be used by everyone with ease.
        
        ## Why p2py?
        
        That's why:
        
        - **It's plug-and-play**,
        - **It's easy to use**,
        - **It's customizable**
        
        
        
        ## Features
        
        P2py is packed with many usefull features that will help you build your p2p app faster:
        
        - **TCP Hole Punching**
        - **Chord routing system** (So you can connect to other node jus using it's numeric ID)
        - **Temporary / constant connections**
        - **Sending any type of data** (that can be represented in bytes)
        - **Messages**
        - **Requests** (p2py's experimental approach that will save you some time)
        - **Built-in text message type**
        - **Tools for defining and handling your own message types**
        
        ## Installation
        
        Install with `pip` using the command:
        
        ```
        $ pip install p2py
        ```
        
        
        
        ## Simple examples
        
        ### Joining the network and sending text message
        
        Node B joins the network of Node A
        
        **Node A** (172.17.0.2:4444)  UUID 0
        
        ```python
        import p2py, time
        
        node = p2py.Node(4444) #Create a node listening on port 4444
        node.start() #Start the node
        
        while True: #Wait forever
        	time.sleep(1) 
        	
        #Listening on 172.17.0.2:4444
        #(172.11.0.3:4444) -> "Hi!"
        ```
        
        **Node B** (172.11.0.3:4445) UUID 1
        
        ```python
        import p2py, time
        
        node = p2py.Node(4445) #Create a node listening on port 4444
        node.start() #Start the node
        
        node.join_network((('172.17.0.2', 4444))) #Join the network of Node A
        while not node.joined(): #Wait until the node joins the network
        	time.sleep(1) 
        
        msg = {	#Construct a message
            'type' : 'text',
            'data' : "Hi!"
        }
        node.send_to_UUID(UUID=0, msg=msg) #Send a message to Node A
        	
        #Listening on 172.11.0.3:4444
        #Successfully joined the network! Your UUID is 1
        #Sent message to UUID 0
        ```
        
        ### Define custom request type and send request
        
        In this example I will define a custom request type thet will add 1 to a requested number and return the result bact to requesting peer.
        
        **Node A** (172.17.0.2:4444) 
        
        ```python
        import p2py, time
        
        node = p2py.Node(4444) #Create a node listening on port 4444
        
        def handle_add(node, conn, request): #Define a handler
        	n = request.contents['data'] #Get data from request
        	n_plus_one = n + 1 #Process the data
        	resp = { #Construct a response
                'type' : 'ADD RESP',
                'data' : n_plus_one
        	}
        	request.respond(resp)  #Respond
        
        node.add_handler("ADD", handle_add) #Assign the handler to "ADD" message type
        
        node.start() #Start the node
        
        while True: #Wait forever
        	time.sleep(1) 
        	
        #Listening on 172.17.0.2:4444
        ```
        
        **Node B** (172.11.0.3:4445)
        
        ```python
        import p2py, time
        
        node = p2py.Node(4445) #Create a node listening on port 4444
        node.start() #Start the node
        
        node.join_network((('172.17.0.2', 4444))) #Join the network of Node A
        while not node.joined(): #Wait until the node joins the network
        	time.sleep(1) 
        
        msg = {	#Construct a request
            'type' : 'ADD',
            'data' : 17
        }
        resp = node.request(UUID=0, request_msg=msg) #Send a request to Node A and receive response
        result = resp['data']
        print(f"17 + 1 = {result}")
        
        
        #Listening on 172.11.0.3:4444
        #Successfully joined the network! Your UUID is 1
        #Sent message to UUID 0
        #17 + 1 = 18
        ```
        
        ## 
        
        ## Documentation
        
        This is documentation of some high level functions (there is a lot more)
        
        ### p2py.Node(*port*, *host[opt]*)
        
        > Creates node object. It will listen for connections on specified ***port [int]***. If ***host [str]*** was not specified it will run on localhost (127.0.0.1)
        
        **Example:**
        
        ```python
        example_node = Node(4444)
        ```
        
        
        
        #### Functions:
        
        ##### *Node***.connect_to_network(*address_list*)**
        
        > Connects node to network of peer which ***address_list [tuple]*** was given. Argument ***address_list*** is a list of 2-tuples of host (str) and port (int): **(HOST [str], PORT [int])**.
        
        **Example:**
        
        ```python
        example_node.connect_to_network([('127.0.0.1', 1234)])
        ```
        
        
        
        ##### *Node*.send_to_UUID(*UUID*, *message*)
        
        > Creates a temporary connection with ***UUID [Int]*** (that means it will be closed after sending the message) and sends **message [dict]**.
        >
        > **Message** is a JSON dict it this form:
        >
        > ```python
        > {
        >     'type' : MESSAGE_TYPE,
        >     'data' : MESSAGE_DATA
        > }
        > ```
        >
        > 
        
        **Example:**
        
        ```python
        message = {
            'type' : 'TEXT',
            'data' : 'Hello!'
        }
        example_node.send_to_UUID(7, message)
        #sends hello to UUID 7
        ```
        
        ##### 
        
        ##### *Node*.send_to_address(*address*, *message*)
        
        > Creates a temporary connection with ***address [2-tuple]*** (that means it will be closed after sending the message) and sends **message [dict]**.
        
        **Example:**
        
        ```python
        message = {
            'type' : 'TEXT',
            'data' : 'Hello!'
        }
        example_node.send_to_address(('127.0.0.1', 1234), message)
        #sends hello to 127.0.0.1:1234
        ```
        
        ##### 
        
        ##### *Node*.send_to_connection(*connection*, *message*)
        
        > Sends **message *[dict]*** to **connection*[Connection]***.
        
        **Example:**
        
        ```python
        message = {
            'type' : 'TEXT',
            'data' : 'Hello!'
        }
        conn = get_connection_object() #this is a pseudo function. Don't try it as it doesnt exist
        example_node.send_to_connection(conn, message)
        #sends hello to conn
        ```
        
        
        
        ##### *Node*.request(*UUID[opt]*, *address[opt]*, *connection[opt]*, *request_msg*)
        
        > Sends **request *[Request]*** to **UUID*[Int]*** OR **address*[2-tuple]*** OR **connection*[Connection]*** (at least one has to be specified). It returns ***dict*** as a response or ***NoneType*** if there is no response.
        >
        > The requested node receives ***Request object***. You can learn about handling requests [in this section]()
        
        **Example:**
        
        ```python
        request = {
            'type' : 'ADD',
            'data' : 17
        }
        
        resp = example_node.request(UUID=7, request_msg=request)
        print(f"17 + 1 = {resp['data']}")
        ```
        
        ##### 
        
        ##### *Node*.send_to_peer_book(*message*, *exclude [opt]*)
        
        > Sends **message [dict]** to all peers in your peer book optionally excluding UUIDs[Int] in **exclude [List]**
        
        **Example:**
        
        ```python
        message = {
            'type' : 'TEXT',
            'data' : 'Hello peer book!'
        }
        example_node.send_to_peer_book(message)
        #sends "Hello peer book!" to peer book
        ```
        
        
        
        ##### *Node*.close_all_connections()
        
        > Closes all connections. It's synonymous to leaving the network
        
        **Example:**
        
        ```python
        example_node.close_all_connections()
        #left the network
        ```
        ##### *Node*.add_handler(*message_type[str]*, *handler[func]*)
        
        > Defines a handler for a given ***message_type***. It takes 2 arguments: ***message_type*** and ***handler*** function.
        >
        > ***Handler*** function has to take 3 arguments: 
        > - **node** - a pointer to the local node,
        > - **conn** - Connection object from which the request was sent,
        > - **request** - Request object sent by requesting node.
        
        **Example:**
        
        ```python
        def some_function(node, conn, request):
        	#do something
        
        node.add_handler("some type", some_function)
        node.start()
        ```
        
        
        #### Variables
        
        ##### *Node*.UUID [Int]
        
        > This variable holds node's UUID. It's set to `None ` when node is not connected to any network.
        
        **Example:**
        
        ```python
        print(example_node.UUID)
        #3
        ```
        
        
        
        ##### *Node*.network_size [Int]
        
        > This variable holds info about the number of peers in the network Node is connected to
        
        **Example:**
        
        ```python
        print(example_node.network_size)
        #77
        ```
        
        ### p2py.Request(*callback_address*, *contents*)
        
        > Creates request object
        
        ##### *Request*.respond(*response[dict]*)
        
        > Sends the ***response*** to the requester.
        
        **Example:**
        
        ```python
        msg = {
            'type' : 'SOME RESP',
            'data' : 'some data'
        }
        
        request.respond(msg)
        ```
        
        ##### *Request*.bounce(*address[opt]*, *UUID[opt]*)
        
        > Sends the requests to another node specified by either ***address*** OR ***UUID***. 
        >
        > The request will be processed by another peer **but the response will be sent to the same requester**.
        
        
        **Example:**
        
        ```python
        #Oh no! I can't answer the request. Maybe UUID 7 knows the answer
        
        request.bounce(UUID=7)
        ```
        
        
        ### Message types
        
        > There are many types of messages that do different things. These are some high-level ones:
        
        ### type TEXT
        
        ```python
        message = {
            'type' : 'TEXT',
            'data' : text_message
        }
        ```
        
        
Keywords: p2p,peer to peer,ipds
Platform: all
Classifier: Development Status :: 3 - Alpha
Classifier: Topic :: Software Development :: Build Tools
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: System :: Networking
Description-Content-Type: text/markdown
