The P2PD REST API

Starting the server

Start the REST API server::

python3 -m p2pd.rest_api

Running this command will start the server on http://127.0.0.1:12333/ The server has no password and will only allow requests from an ‘origin’ of 127.0.0.1 or null. The null origin occurs when a HTML document is opened locally. If a website you visit tries to use the P2PD API your browser will include the domain name as an origin which the server will reject.

Making your first request

To check the server you can visit the version resource.

curl http://localhost:12333/version

You should see a JSON response.

{
   "author": "Matthew@Roberts.PM",
   "title": "P2PD",
   "version": "0.1.0"
}

Looking up your peer’s address

You’ll want to know how to get your peers address. The address is used to try connect to a peer.

curl http://localhost:12333/p2p/addr

Sample JSON response.

{
   "addr": "[0,1.3.3.7,192.168.21.21,58959,3,2,0]-0-looongcatislong",
   "error": 0
}

Now lets try connect to it

Peer addresses will be passed to the ‘open’ resource. A number of strategies are used to try establish connections. The order of success will define how fast connections can be opened.

curl "http://localhost:12333/p2p/open/name_for_new_con/addr_of_node"

Please note how the connection is given a name. The name is used to identify connections rather than using IDs. You will need to remember names for later API calls. Should you wish to test P2P connections you can also use ‘self’ to connect to yourself.

curl http://localhost:12333/p2p/open/con_name/self

The JSON response shows information on the new connection.

{
   "fd": 1060,
   "if": {
      "name": "Intel(R) Wi-Fi 6 AX200 160MHz"
      "offset": 0
   },
   "laddr": [
      "192.168.21.21",
      58537
   ],
   "name": "con_name",
   "raddr": [
      "192.168.21.21",
      58959
   ],
   "route": {
      "af": 2,
      "ext_ips": [
            {
               "af": 2,
               "cidr": 32,
               "ip": "1.3.3.7"
            }
      ],
      "nic_ips": [
            {
               "af": 2,
               "cidr": 32,
               "ip": "192.168.21.21"
            }
      ]
   },
   "strategy": "direct connect"
}

You can see the information includes details like the file descriptor number of the socket, your external address for the socket, and the technique that worked to establish the connection.

Text-based send and receive

Let’s start with something simple. For these examples I’ll assume you want to work with a simple text-based protocol. In reality you may be building something far more complex and require more flexibility but this is a good starting point.

Sending text:

The node server has a built-in echo server. We’ll be using this protocol to test out some commands.

curl "http://localhost:12333/p2p/send/con_name/ECHO%20hello,%20world!"
{
   "error": 0,
   "name": "con_name",
   "sent": 18
}

Receiving text:

curl "http://localhost:12333/p2p/recv/con_name"
{
   "data": "hello, world!",
   "error": 0,
   "client_tup": [
      "192.168.21.200",
      54925
   ]
}

Binary send and receive

So far all API methods have used the GET method. GET is ideal for regular, text-based data where you don’t have to worry too much about encoding. But if you want a more flexible approach that can also deal with binary data it’s necessary to visit the POST method. These next examples will be written in Javascript using the Jquery library.

async function binary_push()
{
   // Binary data to send -- outside printable ASCII.
   // Will send an echo request to the Node server.
   var x = new Uint8Array(9);
   x[0] = 69; // 'E'
   x[1] = 67; // 'C'
   x[2] = 72; // 'H'
   x[3] = 79; // 'O'
   x[4] = 32; // ' '
   x[5] = 200; // ... binary codes,
   x[6] = 201;
   x[7] = 202;
   x[8] = 203;

   // Send as encoded binary data using POST to API.
   // This demonstrates that binary POST works.
   var url = 'http://localhost/p2p/binary/con_name';
   var out = await $.ajax({
      url: url,
      type: "POST",
      data: x,
      contentType: "application/octet-stream",
      dataType: "text",
      processData: false
   });
}
{
   "error": 0,
   "name": "con_name",
   "sent": 9
}

Here’s what it looks like to receive the binary back again.

async function binary_pull()
{
   // Receive back binary buffer.
   // Node server should echo back the last 4 bytes.
   var url = 'http://localhost/p2p/binary/con_name';
   out = await $.ajax({
      url: url,
      type: 'GET',
      processData: 'false',
      dataType: 'binary',
      xhrFields:{
         responseType: 'blob'
      },
      headers: { 'X-Requested-With': 'XMLHttpRequest' }
   });

   // Convert output blob to array buffer.
   // Then convert that to a Uint8Array.
   mem_view = await out.arrayBuffer();
   out_bytes = new Uint8Array(mem_view);
}

By the way: these examples use el8 async await syntax. This avoids callback hell which is low IQ. If you don’t understand async-style code it’s time for you to learn! All code in P2PD is async.

Bidirectional relay pipes

Theses simple send/receive calls are examples of push and pull APIs. In other words – its up to you to check whether messages are available. Such an approach might be fine for simple scripts but it’s a little inefficient having to constantly check or ‘poll’ for new messages. Fortunately, P2PD has you covered. There is a special API method that converts a HTTP connection into a two-way relay.

What I mean by this is if you make a HTTP request to a named connection P2PD will relay data you send to that connection to the named connection and back again. This is very useful because it allows you to write asynchronous code that only has to handle data when it’s available. Almost like a regular connection you made yourself.

The catch is I can’t write the code for you exactly as I don’t know what language you’ll be using with the API – but so long as you know how to make a connection and send a HTTP request the process is quite straight-forwards.

  1. Make a SOCK_STREAM socket. Choose AF_INET for the address family.

  2. Connect the socket to localhost on port 12333.

  3. Send a HTTP GET request to /p2p/pipe/con_name. Data to send:

GET /p2p/pipe/con_name HTTP/1.1\r\n
Origin: null\r\n\r\n

The connection is closed on error. You can test it works by sending ‘ECHO hello world’ down the connection and checking for the response. As this is a relay between an associated connection to a peer’s node server which implements echo.

Publish-subscribe

To learn about how to use the REST API for topic filtering please read the Queues page.