heroforge-core 0.2.2

Pure Rust core library for reading and writing Fossil SCM repositories
Documentation
//! Simple QUIC connectivity test
//!
//! Tests that client and server can communicate at all.

use heroforge_core::sync::quic::{QuicClient, QuicServer};
use heroforge_core::Repository;
use std::path::PathBuf;
use tokio::runtime::Runtime;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() < 2 {
        eprintln!("Usage: {} <source.forge>", args[0]);
        std::process::exit(1);
    }

    let source_path = PathBuf::from(&args[1]);

    // Create temp dest
    let temp_dir = tempfile::tempdir().expect("temp dir");
    let dest_path = temp_dir.path().join("dest.forge");

    // Copy project code
    let source_repo = Repository::open(&source_path).expect("open source");
    let project_code = source_repo.project_code().expect("project code");
    let dest_repo = Repository::init(&dest_path).expect("init dest");
    dest_repo
        .database()
        .connection()
        .execute(
            "UPDATE config SET value = ?1 WHERE name = 'project-code'",
            [&project_code],
        )
        .expect("set project code");
    drop(dest_repo);
    drop(source_repo);

    println!("Source: {}", source_path.display());
    println!("Dest: {}", dest_path.display());
    println!("Project code: {}", project_code);

    // Single runtime, use tokio::spawn for concurrency
    let rt = Runtime::new().expect("runtime");

    rt.block_on(async {
        // Bind server
        let server = QuicServer::bind("127.0.0.1:0").expect("bind");
        let addr = server.local_addr().expect("addr").to_string();
        println!("Server bound to {}", addr);

        // Spawn server task
        let source_path_clone = source_path.clone();
        let server_task = tokio::task::spawn_blocking(move || {
            let rt = Runtime::new().expect("rt");
            rt.block_on(async {
                let repo = Repository::open(&source_path_clone).expect("open");
                println!("Server: waiting for connection...");
                server.handle_sync(&repo, &source_path_clone).await
            })
        });

        // Give server time to be ready
        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;

        // Run client
        println!("Client: connecting to {}...", addr);
        let dest_path_clone = dest_path.clone();
        let client_result = tokio::task::spawn_blocking(move || {
            let rt = Runtime::new().expect("rt");
            rt.block_on(async {
                let repo = Repository::open_rw(&dest_path_clone).expect("open");
                QuicClient::sync(&repo, &dest_path_clone, &addr).await
            })
        })
        .await
        .expect("client task");

        match client_result {
            Ok(stats) => println!(
                "Client: SUCCESS! Received {} artifacts",
                stats.artifacts_received
            ),
            Err(e) => println!("Client: FAILED: {}", e),
        }

        let server_result = server_task.await.expect("server task");
        match server_result {
            Ok(stats) => println!("Server: SUCCESS! Sent {} artifacts", stats.artifacts_sent),
            Err(e) => println!("Server: FAILED: {}", e),
        }
    });
}