p2p-foundation 0.1.8

Complete P2P networking foundation with flexible contacts panel, collapsible system menu, sparkly interactive help, DHT inboxes with infinite TTL, embedded Flutter PWA with auto-scroll chat, native app support, three-word addresses, and built-in AI capabilities
Documentation
//! P2P Foundation Node Binary
//!
//! Command-line interface for running P2P Foundation nodes.
//! This binary provides a user-friendly way to start and configure P2P nodes.

use anyhow::Result;
use clap::{Arg, Command};
use std::path::PathBuf;
use tracing::{info, warn};

/// CLI configuration for the P2P node
#[derive(Debug)]
struct NodeCliConfig {
    /// Port to listen on
    port: u16,
    /// Enable IPv6
    enable_ipv6: bool,
    /// Enable MCP server
    enable_mcp: bool,
    /// Bootstrap peers to connect to
    bootstrap_peers: Vec<String>,
    /// Configuration file path
    config_file: Option<PathBuf>,
    /// Log level
    log_level: String,
}

impl Default for NodeCliConfig {
    fn default() -> Self {
        Self {
            port: 9000,
            enable_ipv6: true,
            enable_mcp: true,
            bootstrap_peers: Vec::new(),
            config_file: None,
            log_level: "info".to_string(),
        }
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Parse command line arguments
    let matches = Command::new("p2p-node")
        .version(env!("CARGO_PKG_VERSION"))
        .author("David Irvine <david@yourdomain.com>")
        .about("P2P Foundation Node - Next-generation peer-to-peer networking")
        .arg(
            Arg::new("port")
                .short('p')
                .long("port")
                .value_name("PORT")
                .help("Port to listen on")
                .default_value("9000")
        )
        .arg(
            Arg::new("ipv6")
                .long("ipv6")
                .help("Enable IPv6 support")
                .action(clap::ArgAction::SetTrue)
        )
        .arg(
            Arg::new("no-ipv6")
                .long("no-ipv6")
                .help("Disable IPv6 support")
                .action(clap::ArgAction::SetTrue)
                .conflicts_with("ipv6")
        )
        .arg(
            Arg::new("mcp")
                .long("mcp")
                .help("Enable MCP server")
                .action(clap::ArgAction::SetTrue)
        )
        .arg(
            Arg::new("no-mcp")
                .long("no-mcp")
                .help("Disable MCP server")
                .action(clap::ArgAction::SetTrue)
                .conflicts_with("mcp")
        )
        .arg(
            Arg::new("bootstrap")
                .short('b')
                .long("bootstrap")
                .value_name("ADDR")
                .help("Bootstrap peer address (can be specified multiple times)")
                .action(clap::ArgAction::Append)
        )
        .arg(
            Arg::new("config")
                .short('c')
                .long("config")
                .value_name("FILE")
                .help("Configuration file path")
        )
        .arg(
            Arg::new("log-level")
                .short('l')
                .long("log-level")
                .value_name("LEVEL")
                .help("Log level (trace, debug, info, warn, error)")
                .default_value("info")
        )
        .arg(
            Arg::new("daemon")
                .short('d')
                .long("daemon")
                .help("Run as daemon")
                .action(clap::ArgAction::SetTrue)
        )
        .get_matches();

    // Parse configuration
    let mut config = NodeCliConfig::default();
    
    if let Some(port_str) = matches.get_one::<String>("port") {
        config.port = port_str.parse()
            .map_err(|_| anyhow::anyhow!("Invalid port number: {}", port_str))?;
    }
    
    if matches.get_flag("ipv6") {
        config.enable_ipv6 = true;
    } else if matches.get_flag("no-ipv6") {
        config.enable_ipv6 = false;
    }
    
    if matches.get_flag("mcp") {
        config.enable_mcp = true;
    } else if matches.get_flag("no-mcp") {
        config.enable_mcp = false;
    }
    
    if let Some(bootstrap_peers) = matches.get_many::<String>("bootstrap") {
        config.bootstrap_peers = bootstrap_peers.map(|s| s.to_string()).collect();
    }
    
    if let Some(config_file) = matches.get_one::<String>("config") {
        config.config_file = Some(PathBuf::from(config_file));
    }
    
    if let Some(log_level) = matches.get_one::<String>("log-level") {
        config.log_level = log_level.to_string();
    }

    // Initialize logging
    let log_filter = format!("p2p_foundation={}", config.log_level);
    tracing_subscriber::fmt()
        .with_env_filter(tracing_subscriber::EnvFilter::new(log_filter))
        .init();

    info!("Starting P2P Foundation Node v{}", env!("CARGO_PKG_VERSION"));
    info!("Configuration: {:?}", config);

    // Check if running as daemon
    if matches.get_flag("daemon") {
        info!("Running in daemon mode");
        // In a real implementation, this would fork the process
    }

    // Start the P2P node
    run_node(config).await
}

async fn run_node(config: NodeCliConfig) -> Result<()> {
    // This is a placeholder implementation since the actual P2P Foundation
    // library is not yet implemented. In the real implementation, this would:
    // 1. Create a P2PNode with the specified configuration
    // 2. Start the node and MCP server
    // 3. Handle graceful shutdown on SIGTERM/SIGINT
    
    warn!("P2P Foundation library not yet implemented");
    warn!("This is a placeholder binary for development and testing");
    
    info!("Would start P2P node with:");
    info!("  - Listen port: {}", config.port);
    info!("  - IPv6 enabled: {}", config.enable_ipv6);
    info!("  - MCP server: {}", config.enable_mcp);
    info!("  - Bootstrap peers: {:?}", config.bootstrap_peers);
    
    if let Some(config_file) = config.config_file {
        info!("  - Config file: {:?}", config_file);
    }

    // Simulate running node
    info!("Node started successfully (placeholder)");
    info!("Press Ctrl+C to stop the node");
    
    // Wait for shutdown signal
    tokio::signal::ctrl_c().await?;
    
    info!("Received shutdown signal, stopping node...");
    info!("Node stopped gracefully");
    
    Ok(())
}

// Placeholder for when the actual library is implemented
// 
// use p2p_foundation::{P2PNode, NodeConfig};
// 
// async fn run_node(config: NodeCliConfig) -> Result<()> {
//     let node_config = NodeConfig {
//         listen_addrs: vec![
//             if config.enable_ipv6 {
//                 format!("/ip6/::/tcp/{}", config.port).parse()?
//             } else {
//                 format!("/ip4/0.0.0.0/tcp/{}", config.port).parse()?
//             }
//         ],
//         enable_ipv6: config.enable_ipv6,
//         enable_mcp_server: config.enable_mcp,
//         bootstrap_peers: config.bootstrap_peers.into_iter()
//             .map(|addr| addr.parse())
//             .collect::<Result<Vec<_>, _>>()?,
//         ..Default::default()
//     };
//     
//     let node = P2PNode::new(node_config).await?;
//     
//     info!("P2P node started successfully");
//     info!("Node ID: {}", node.peer_id());
//     info!("Listening on: {:?}", node.listen_addrs().await?);
//     
//     if config.enable_mcp {
//         let mcp_server = node.mcp_server().await?;
//         info!("MCP server available with {} tools", 
//               mcp_server.list_tools().await?.len());
//     }
//     
//     // Set up graceful shutdown
//     let shutdown = async {
//         tokio::signal::ctrl_c().await.ok();
//         info!("Received shutdown signal");
//     };
//     
//     // Run the node until shutdown
//     tokio::select! {
//         result = node.run() => {
//             if let Err(e) = result {
//                 error!("Node error: {}", e);
//                 return Err(e);
//             }
//         }
//         _ = shutdown => {
//             info!("Shutting down gracefully...");
//         }
//     }
//     
//     node.shutdown().await?;
//     info!("Node stopped successfully");
//     
//     Ok(())
// }