Files
p2ns/docs/EXAMPLES.md
T

17 KiB

P2NS API Usage Examples

This document provides practical examples for using the P2NS Admin API.

Table of Contents

Basic Operations

Health Check

# Liveness probe
curl -k https://p2ns.admin/api/health

# Readiness probe
curl -k https://p2ns.admin/api/health?probe=readiness

Get System Status

curl -k https://p2ns.admin/api/status

Get Metrics

curl -k https://p2ns.admin/api/stats

Domain Management

Add a Domain

curl -k -X POST https://p2ns.admin/api/add-domain \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.tld",
    "hash": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a",
    "ssl": false
  }'

List All Domains

curl -k https://p2ns.admin/api/resolved-domains

Remove a Domain

curl -k -X POST https://p2ns.admin/api/remove-domain \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.tld"
  }'

Holesail Management

Create a Holesail Server

curl -k -X POST https://p2ns.admin/api/holesail-create \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-server",
    "port": 8080,
    "host": "0.0.0.0",
    "secure": true,
    "udp": false,
    "log": 1,
    "domain": "example.tld"
  }'

List Holesail Servers

curl -k https://p2ns.admin/api/holesail-servers

Restart a Holesail Server

curl -k -X POST https://p2ns.admin/api/holesail-restart \
  -H "Content-Type: application/json" \
  -d '{
    "id": "abc123"
  }'

Create a Holesail Client

curl -k -X POST https://p2ns.admin/api/holesail-client-create \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.tld",
    "key": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a",
    "port": 8080,
    "protocol": "tcp"
  }'

Local DNS Records

Add an A Record

curl -k -X POST https://p2ns.admin/api/add-local-dns \
  -H "Content-Type: application/json" \
  -d '{
    "name": "local.example",
    "type": "A",
    "ttl": 3600,
    "data": "192.168.1.100"
  }'

Add an MX Record

curl -k -X POST https://p2ns.admin/api/add-local-dns \
  -H "Content-Type: application/json" \
  -d '{
    "name": "mail.example",
    "type": "MX",
    "ttl": 3600,
    "preference": 10,
    "exchange": "mx.example.com"
  }'

Add an SRV Record

curl -k -X POST https://p2ns.admin/api/add-local-dns \
  -H "Content-Type: application/json" \
  -d '{
    "name": "_service._tcp.example",
    "type": "SRV",
    "ttl": 3600,
    "priority": 0,
    "weight": 5,
    "port": 8080,
    "target": "server.example.com"
  }'

Update a DNS Record

curl -k -X POST https://p2ns.admin/api/update-local-dns \
  -H "Content-Type: application/json" \
  -d '{
    "index": 0,
    "record": {
      "name": "local.example",
      "type": "A",
      "ttl": 7200,
      "data": "192.168.1.101"
    }
  }'

Delete a DNS Record

curl -k -X POST https://p2ns.admin/api/delete-local-dns \
  -H "Content-Type: application/json" \
  -d '{
    "index": 0
  }'

Certificate Management

Generate a Certificate

curl -k -X POST https://p2ns.admin/api/generate-cert \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.tld"
  }'

Get Certificate Details

curl -k "https://p2ns.admin/api/cert-details?domain=example.tld"

Regenerate Certificate

curl -k -X POST https://p2ns.admin/api/regenerate-cert \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.tld"
  }'

Regenerate Root CA

curl -k -X POST https://p2ns.admin/api/regenerate-ca

WebSocket Examples

JavaScript/Node.js

const WebSocket = require('ws');

const ws = new WebSocket('wss://p2ns.admin/ws', {
  rejectUnauthorized: false // Accept self-signed certificate
});

ws.on('open', () => {
  console.log('Connected to P2NS WebSocket');
});

ws.on('message', (data) => {
  const message = JSON.parse(data);
  console.log('Received:', message);
  
  switch (message.type) {
    case 'log':
      console.log(`[${message.level}] ${message.message}`);
      break;
    case 'update-database':
      console.log('Database updated, refresh domains');
      break;
    case 'update-peers':
      console.log('Peers updated');
      break;
  }
});

ws.on('error', (error) => {
  console.error('WebSocket error:', error);
});

ws.on('close', () => {
  console.log('WebSocket closed');
});

Python

import asyncio
import websockets
import ssl
import json

async def connect_p2ns():
    ssl_context = ssl.create_default_context()
    ssl_context.check_hostname = False
    ssl_context.verify_mode = ssl.CERT_NONE
    
    uri = "wss://p2ns.admin/ws"
    
    async with websockets.connect(uri, ssl=ssl_context) as websocket:
        print("Connected to P2NS WebSocket")
        
        async for message in websocket:
            data = json.loads(message)
            print(f"Received: {data}")
            
            if data['type'] == 'log':
                print(f"[{data['level']}] {data['message']}")
            elif data['type'] == 'update-database':
                print("Database updated")

asyncio.run(connect_p2ns())

Error Handling

Handling Rate Limits

async function makeRequest(url, options) {
  try {
    const response = await fetch(url, options);
    
    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After');
      console.log(`Rate limited. Retry after ${retryAfter} seconds`);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      return makeRequest(url, options); // Retry
    }
    
    if (!response.ok) {
      const error = await response.text();
      throw new Error(error);
    }
    
    return await response.json();
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}

Handling Connection Errors

async function robustRequest(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      if (response.ok) {
        return await response.json();
      }
      throw new Error(`HTTP ${response.status}`);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
}

Troubleshooting

Certificate Issues

If you encounter certificate errors:

# On macOS, trust the CA manually:
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./certs/ca.cert.pem

# On Linux (system store + NSS for Chrome — requires libnss3-tools):
sudo cp ./certs/ca.cert.pem /usr/local/share/ca-certificates/p2ns-ca.crt
sudo update-ca-certificates
mkdir -p ~/.pki/nssdb
certutil -d sql:$HOME/.pki/nssdb -D -n "P2NS CA" 2>/dev/null || true
certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "P2NS CA" -i ./certs/ca.cert.pem

# On Windows (PowerShell as Administrator):
certutil -addstore -f "ROOT" .\certs\ca.cert.pem

DNS Resolution Issues

Test DNS resolution:

# Query P2P domain
dig @127.0.0.1 example.tld

# Query with specific type
dig @127.0.0.1 example.tld AAAA

# Query local DNS record
dig @127.0.0.1 local.example A

Connection Issues

Check if services are running:

# Check health
curl -k https://p2ns.admin/api/health

# Check status
curl -k https://p2ns.admin/api/status

# View logs via WebSocket or admin interface

Backup Operations

List All Backups

curl -k https://p2ns.admin/api/backups

Create Manual Backup

curl -k -X POST https://p2ns.admin/api/backups/create

Restore from Backup

curl -k -X POST https://p2ns.admin/api/backups/restore \
  -H "Content-Type: application/json" \
  -d '{
    "backupName": "backup-20240101-000000"
  }'

Get Backup Metadata

curl -k https://p2ns.admin/api/backups/backup-20240101-000000/metadata

Delete Backup

curl -k -X DELETE https://p2ns.admin/api/backups/backup-20240101-000000

Diagnostics Examples

DNS Lookup

# A record
curl -k -X POST https://p2ns.admin/api/diagnostics/dns-lookup \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "type": "A"
  }'

# MX record
curl -k -X POST https://p2ns.admin/api/diagnostics/dns-lookup \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "type": "MX"
  }'

Ping (Non-streaming)

curl -k -X POST https://p2ns.admin/api/diagnostics/ping \
  -H "Content-Type: application/json" \
  -d '{
    "target": "8.8.8.8",
    "count": 4
  }'

Ping (Streaming)

curl -k -X POST https://p2ns.admin/api/diagnostics/ping \
  -H "Content-Type: application/json" \
  -d '{
    "target": "8.8.8.8",
    "count": 4,
    "stream": true
  }'

Traceroute

curl -k -X POST https://p2ns.admin/api/diagnostics/traceroute \
  -H "Content-Type: application/json" \
  -d '{
    "target": "8.8.8.8",
    "stream": true
  }'

Connection Test

curl -k -X POST https://p2ns.admin/api/diagnostics/connection-test \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "port": 443
  }'

Bandwidth Information

curl -k https://p2ns.admin/api/diagnostics/bandwidth

Stats and Metrics Examples

Get Current Stats

curl -k https://p2ns.admin/api/stats

Get Historical Metrics

# Last hour
curl -k "https://p2ns.admin/api/stats/historical?minutes=60"

# Last 24 hours
curl -k "https://p2ns.admin/api/stats/historical?minutes=1440"

JavaScript Stats Monitoring

// One-shot HTTP load (admin UI uses this once on tab open)
async function getStatsOnce() {
  const response = await fetch('https://p2ns.admin/api/stats');
  return response.json();
}

// Live updates via WebSocket (preferred)
const ws = new WebSocket('wss://p2ns.admin/ws');
ws.onopen = () => ws.send(JSON.stringify({ type: 'subscribe-stats' }));
ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.type === 'stats-snapshot') {
    console.log('Core RPC:', msg.stats?.core?.summary);
    console.log('Plugin RPC protocols:', msg.stats?.pluginRpc?.totalProtocols);
  }
};

Tail logs over WebSocket

const ws = new WebSocket('wss://p2ns.admin/ws');
ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'subscribe-log', channel: 'dns', lines: 500 }));
};
ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.type === 'file-log' && msg.channel === 'dns') console.log(msg.message);
};

Consensus Examples

Get Sidecar Status

curl -k https://p2ns.admin/api/consensus/status

Get Consensus State for a Domain

curl -k https://p2ns.admin/api/consensus/example.tld

Get Consensus Metrics

curl -k https://p2ns.admin/api/consensus/metrics

Force Consensus Recalculation

# Recalculate all domains
curl -k -X POST https://p2ns.admin/api/consensus/recalculate

# Recalculate specific domain
curl -k -X POST https://p2ns.admin/api/consensus/recalculate/example.tld

JavaScript: Monitor Consensus State

async function getConsensusState(domain) {
  const response = await fetch(`https://p2ns.admin/api/consensus/${encodeURIComponent(domain)}`);
  const state = await response.json();
  
  console.log(`Domain: ${domain}`);
  console.log(`Status: ${state.status}`);
  console.log(`Quorum Met: ${state.quorumMet}`);
  console.log(`Vote Counts:`, state.voteCounts);
  
  if (state.status === 'resolved') {
    console.log(`Resolved Hash: ${state.hash}`);
    console.log(`Winner: ${state.resolvedClaimant}`);
  } else if (state.status === 'insufficient_quorum') {
    console.log(`Need ${state.minVotes} votes, have ${state.totalVotes}`);
  } else if (state.status === 'tie') {
    console.log('Tie detected, tie-breaker applied');
  }
  
  return state;
}

// Check consensus for a domain
getConsensusState('example.tld');

JavaScript: Monitor Consensus Metrics

async function getConsensusMetrics() {
  const response = await fetch('https://p2ns.admin/api/consensus/metrics');
  const metrics = await response.json();
  
  console.log('Total Resolutions:', metrics.resolutions);
  console.log('Quorum Failures:', metrics.quorumFailures);
  console.log('Ties:', metrics.ties);
  console.log('Total Votes:', metrics.totalVotes);
  console.log('Avg Votes per Domain:', metrics.avgVotesPerDomain);
  
  // Per-domain statistics
  metrics.domainResolutions.forEach(({ domain, resolved, failed }) => {
    console.log(`${domain}: ${resolved} resolved, ${failed} failed`);
  });
  
  return metrics;
}

// Get metrics every minute
setInterval(getConsensusMetrics, 60000);

JavaScript: Monitor Domain Resolution Status

async function monitorDomainResolution(domain, interval = 5000) {
  const checkStatus = async () => {
    const state = await getConsensusState(domain);
    
    if (state.status === 'resolved') {
      console.log(`✓ ${domain} is resolved: ${state.hash}`);
      return true; // Resolved, stop monitoring
    } else {
      console.log(`⏳ ${domain} status: ${state.status}`);
      if (state.status === 'insufficient_quorum') {
        console.log(`   Need ${state.minVotes} votes, have ${state.totalVotes}`);
      }
      return false; // Not resolved, continue monitoring
    }
  };
  
  // Check immediately
  const resolved = await checkStatus();
  if (resolved) return;
  
  // Continue checking at interval
  const timer = setInterval(async () => {
    const resolved = await checkStatus();
    if (resolved) {
      clearInterval(timer);
    }
  }, interval);
  
  return timer;
}

// Monitor a domain until it's resolved
monitorDomainResolution('example.tld');

Python: Consensus State Monitoring

import requests
import time

def get_consensus_state(domain):
    url = f"https://p2ns.admin/api/consensus/{domain}"
    response = requests.get(url, verify=False)
    return response.json()

def get_consensus_status():
    url = "https://p2ns.admin/api/consensus/status"
    response = requests.get(url, verify=False)
    return response.json()

def get_consensus_metrics():
    url = "https://p2ns.admin/api/consensus/metrics"
    response = requests.get(url, verify=False)
    return response.json()

# Get consensus state
state = get_consensus_state("example.tld")
print(f"Status: {state['status']}")
print(f"Quorum Met: {state['quorumMet']}")
print(f"Vote Counts: {state['voteCounts']}")

# Check sidecar health
status = get_consensus_status()
print(f"Sidecar ready: {status['ready']}, bootstrap: {status['bootstrapComplete']}")

# Get metrics
metrics = get_consensus_metrics()
print(f"Total Resolutions: {metrics['resolutions']}")
print(f"Quorum Failures: {metrics['quorumFailures']}")
if metrics.get('sidecar'):
    print(f"Sidecar domains: {metrics['sidecar']['domainCount']}")

Force Recalculation After Network Changes

async function forceRecalculation(domain = null) {
  const endpoint = domain 
    ? `/api/consensus/recalculate/${encodeURIComponent(domain)}`
    : '/api/consensus/recalculate';
  
  const response = await fetch(`https://p2ns.admin${endpoint}`, {
    method: 'POST'
  });
  
  const result = await response.json();
  console.log(result.message);
  return result;
}

// Recalculate all domains (useful after network topology changes)
await forceRecalculation();

// Recalculate specific domain (useful after adding/removing claims)
await forceRecalculation('example.tld');

Advanced Examples

Batch Domain Addition

const domains = [
  { domain: 'example1.tld', hash: 'hs://...', ssl: false },
  { domain: 'example2.tld', hash: 'hs://...', ssl: true },
  { domain: 'example3.tld', hash: 'hs://...', ssl: false }
];

for (const { domain, hash, ssl } of domains) {
  await fetch('https://p2ns.admin/api/add-domain', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ domain, hash, ssl: ssl || false })
  });
}

Monitoring System Health

async function monitorHealth() {
  const response = await fetch('https://p2ns.admin/api/health?probe=readiness');
  const health = await response.json();
  
  if (health.status !== 'healthy') {
    console.warn('System is degraded:', health);
    // Send alert, etc.
  }
  
  return health;
}

// Monitor every 30 seconds
setInterval(monitorHealth, 30000);