- Fix bidirectional stream handling: responder uses accept_bi() instead of open_bi() so both sides communicate on the same stream - Add live_receive_loop to accept incoming bi-streams during ongoing sync (peer's push loop opens new streams per batch) - Split live_sync_loop into live_push_loop + live_receive_loop running concurrently via tokio::select in new run_live_sync() - Update handle_incoming to run live sync after initial reconciliation - Add direct peer connection via ticket files (EndpointAddr JSON exchange) for local testing without gossip bootstrap - Add CAN_PORT env var override for running multiple CAN instances - Add integration test binary (sync_test.rs): starts 2 CAN services + 2 sync agents, ingests files on each side, verifies bidirectional sync with 4 test cases (A→B, B→A, batch, count match) - Add PowerShell script (run-integration-test.ps1) for one-command test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
41 lines
1.3 KiB
Rust
41 lines
1.3 KiB
Rust
use serde::Deserialize;
|
|
use std::path::Path;
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
pub struct SyncConfig {
|
|
/// Base URL of the local CAN service (e.g. "http://127.0.0.1:3210")
|
|
pub can_service_url: String,
|
|
|
|
/// API key for CAN service's sync endpoints (must match config.sync_api_key)
|
|
pub sync_api_key: String,
|
|
|
|
/// Shared passphrase for peer discovery (all peers must use the same one)
|
|
pub sync_passphrase: String,
|
|
|
|
/// Seconds between polls for new local assets
|
|
#[serde(default = "default_poll_interval")]
|
|
pub poll_interval_secs: u64,
|
|
|
|
/// Optional: path to write this node's ticket to (for direct connection)
|
|
#[serde(default)]
|
|
pub ticket_file: Option<String>,
|
|
|
|
/// Optional: path to a file containing a peer's node ticket (for direct connection).
|
|
/// If set, the agent will read this ticket and connect directly instead of waiting
|
|
/// for gossip discovery. The file is polled until it exists and is non-empty.
|
|
#[serde(default)]
|
|
pub connect_ticket_file: Option<String>,
|
|
}
|
|
|
|
fn default_poll_interval() -> u64 {
|
|
3
|
|
}
|
|
|
|
impl SyncConfig {
|
|
pub fn load(path: &Path) -> anyhow::Result<Self> {
|
|
let contents = std::fs::read_to_string(path)?;
|
|
let config: Self = serde_yaml::from_str(&contents)?;
|
|
Ok(config)
|
|
}
|
|
}
|